Graeme_Grant
Ответ - и да, и нет. Это зависит от того, как данные должны быть сериализованы.
У меня есть два класса конвертеров, один для JSON и один для XML. Оба они называются одинаково,поэтому их легко переключить.
Я опубликую и то, и другое ниже. Версия XML содержит дополнительную информацию,которая должна быть понятной.
JSON с использованием newtownsoft lib
using Newtonsoft.Json;
using System.Collections.Generic;
using System.IO;
namespace DotNet.Shared.Helpers
{
public static class JsonConverter
{
public static string FromClass<T>(T data, bool isEmptyToNull = false, JsonSerializerSettings jsonSettings = null)
{
string response = string.Empty;
if (!EqualityComparer<T>.Default.Equals(data, default(T)))
response = JsonConvert.SerializeObject(data, jsonSettings);
return isEmptyToNull ? (response == "{}" ? "null" : response) : response;
}
public static MemoryStream FromClassToStream<T>(T data, StreamWriter writer, bool isEmptyToNull = false, JsonSerializerSettings jsonSettings = null)
{
var stream = new MemoryStream();
if (!EqualityComparer<T>.Default.Equals(data, default(T)))
{
writer = new StreamWriter(stream);
writer.Write(FromClass(data, isEmptyToNull, jsonSettings));
writer.Flush();
stream.Position = 0;
}
return stream;
}
public static T ToClass<T>(string data, JsonSerializerSettings jsonSettings = null)
{
var response = default(T);
if (!string.IsNullOrEmpty(data))
response = jsonSettings == null
? JsonConvert.DeserializeObject<T>(data)
: JsonConvert.DeserializeObject<T>(data, jsonSettings);
return response;
}
public static T ToClassFromStream<T>(MemoryStream stream)
{
var response = default(T);
if (stream != null)
{
using (var reader = new StreamReader(stream))
using (var jsonReader = new JsonTextReader(reader))
response = (new JsonSerializer()).Deserialize<T>(jsonReader);
}
return response;
}
}
}
XML с помощью Microsoft библиотеки
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Diagnostics;
using System.IO;
using System.Text;
using System.Xml;
using System.Xml.Schema;
using System.Xml.Serialization;
namespace WorkingWithXml
{
class Program
{
static void Main(string[] args)
{
var data = new XmlRootClass
{
Id = 12345567890123456789,
Title = "Widget",
Amount = new AmountType { Value = 123.45, CurrencyID = CurrencyCodeType.USD },
Description = new CData("This is a description with embedded html"),
};
var raw = XmlConverter.FromClass(data);
var newData = XmlConverter.ToClass<XmlRootClass>(raw);
Debugger.Break();
}
}
// Naming a root element
[XmlRoot(ElementName = "Product", IsNullable = false)]
public class XmlRootClass
{
[XmlElement("id123)")]
public ulong Id { get; set; }
public string Title { get; set; }
// a value type element with an attribute
[XmlElement("amt")]
public AmountType Amount { get; set; }
// Custom element data format
[XmlElement("description", typeof(CData))]
public CData Description { get; set; }
// example of optional serialization
[XmlElement, DefaultValue(false)]
public bool IsAvailable { get; set; }
}
public class AmountType
{
[XmlText]
public double Value { get; set; }
//enum type attribute (same works with an XmlElement)
[XmlAttribute("currencyID")]
public string CurrencyID_intern { get; set; }
[XmlIgnore]
public CurrencyCodeType? CurrencyID
{
get
{
return CurrencyID_intern.StringToEnum<CurrencyCodeType?>
(CurrencyCodeType.CustomCode, isNullable: true);
}
set { CurrencyID_intern = value.ToString(); }
}
}
public enum CurrencyCodeType
{
CustomCode, // missing from list
AUD, // Australia dollar
JPY, // Japanese yen
USD, // US dollar
}
public static class EnumExtensions
{
public static T StringToEnum<T>(this string input, T defaultValue = default(T), bool isNullable = false)
{
T outType;
if (string.IsNullOrEmpty(input) &&
isNullable &&
Nullable.GetUnderlyingType(typeof(T)) != null &&
Nullable.GetUnderlyingType(typeof(T)).GetElementType() == null)
return default(T);
return input.EnumTryParse(out outType) ? outType : defaultValue;
}
public static bool EnumTryParse<T>(this string input, out T theEnum)
{
Type type = Nullable.GetUnderlyingType(typeof(T)) != null ? Nullable.GetUnderlyingType(typeof(T)) : typeof(T);
foreach (string en in Enum.GetNames(type))
if (en.Equals(input, StringComparison.CurrentCultureIgnoreCase))
{
theEnum = (T)Enum.Parse(type, input, true);
return true;
}
theEnum = default(T);
return false;
}
}
public static class XmlConverter
{
public static string FromClass<T>(T data, XmlSerializerNamespaces ns = null)
{
string response = string.Empty;
var ms = new MemoryStream();
try
{
ms = FromClassToStream(data, ns);
if (ms != null)
{
ms.Position = 0;
using (var sr = new StreamReader(ms))
response = sr.ReadToEnd();
}
}
finally
{
// don't want memory leaks...
ms.Flush();
ms.Dispose();
ms = null;
}
return response;
}
public static MemoryStream FromClassToStream<T>(T data, XmlSerializerNamespaces ns = null)
{
var stream = default(MemoryStream);
if (!EqualityComparer<T>.Default.Equals(data, default(T)))
{
var settings = new XmlWriterSettings()
{
Encoding = Encoding.UTF8,
Indent = true,
ConformanceLevel = ConformanceLevel.Auto,
CheckCharacters = true,
OmitXmlDeclaration = false
};
XmlSerializer serializer = XmlSerializerFactoryNoThrow.Create(typeof(T));
stream = new MemoryStream();
using (XmlWriter writer = XmlWriter.Create(stream, settings))
{
serializer.Serialize(writer, data, ns);
writer.Flush();
}
stream.Position = 0;
}
return stream;
}
public static T ToClass<T>(string data)
{
var response = default(T);
if (!string.IsNullOrEmpty(data))
{
var settings = new XmlReaderSettings() { IgnoreWhitespace = true };
XmlSerializer serializer = XmlSerializerFactoryNoThrow.Create(typeof(T));
XmlReader reader = XmlReader.Create(new StringReader(data), settings);
response = (T)Convert.ChangeType(serializer.Deserialize(reader), typeof(T));
}
return response;
}
}
// ref: http://stackoverflow.com/questions/1127431/xmlserializer-giving-filenotfoundexception-at-constructor/39642834#39642834
public static class XmlSerializerFactoryNoThrow
{
public static Dictionary<Type, XmlSerializer> cache = new Dictionary<Type, XmlSerializer>();
private static object SyncRootCache = new object();
public static XmlSerializer Create(Type type)
{
XmlSerializer serializer;
lock (SyncRootCache)
if (cache.TryGetValue(type, out serializer))
return serializer;
lock (type) //multiple variable of type of one type is same instance
{
//constructor XmlSerializer.FromTypes does not throw the first chance exception
serializer = XmlSerializer.FromTypes(new[] { type })[0];
}
lock (SyncRootCache) cache[type] = serializer;
return serializer;
}
}
// ref: http://codercorner.blogspot.com.au/2006/11/serialization-and-cdata.html
public class CData : IXmlSerializable
{
public CData()
{ }
public CData(string text)
{
this.text = text;
}
private string text;
public string Text => text;
XmlSchema IXmlSerializable.GetSchema() => null;
void IXmlSerializable.ReadXml(XmlReader reader)
{
text = reader.ReadElementContentAsString();
reader.Read(); // without this line, you will lose value of all other fields
}
void IXmlSerializable.WriteXml(XmlWriter writer)
{
writer.WriteCData(text);
}
public override string ToString() => text;