我可以序列化匿名types为XML?
我明白,匿名types被编译器标记为私有,属性是只读的。 有没有办法将其序列化为XML(没有反序列化)? 它适用于JSON ,我怎样才能用XML来做到这一点?
对不起,你不能。 XML序列化程序几乎只是序列化公共读写types。
请注意,我的回答是关于使用XML序列化程序。 您可以使用其他序列化器成功,特别是使用数据协定序列化器进行试验。
像这样的东西应该让你开始…
class Program { static void Main(string[] args) { var me = new { Hello = "World", Other = new { My = "Object", V = 1, B = (byte)2 } }; var x = me.ToXml(); } } public static class Tools { private static readonly Type[] WriteTypes = new[] { typeof(string), typeof(DateTime), typeof(Enum), typeof(decimal), typeof(Guid), }; public static bool IsSimpleType(this Type type) { return type.IsPrimitive || WriteTypes.Contains(type); } public static XElement ToXml(this object input) { return input.ToXml(null); } public static XElement ToXml(this object input, string element) { if (input == null) return null; if (string.IsNullOrEmpty(element)) element = "object"; element = XmlConvert.EncodeName(element); var ret = new XElement(element); if (input != null) { var type = input.GetType(); var props = type.GetProperties(); var elements = from prop in props let name = XmlConvert.EncodeName(prop.Name) let val = prop.GetValue(input, null) let value = prop.PropertyType.IsSimpleType() ? new XElement(name, val) : val.ToXml(name) where value != null select value; ret.Add(elements); } return ret; } }
…由此产生的XML …
<object> <Hello>World</Hello> <Other> <My>Object</My> <V>1</V> <B>2</B> </Other> </object>
谢谢你,@Matthew和@Martin的出色工作。
我已经做了一些修改来容纳可玩和枚举。 此外,我已经改变了它,使数组元素根据属性+索引的名称命名。
这里是代码,如果任何人有兴趣
public static class ObjectExtensions { #region Private Fields private static readonly Type[] WriteTypes = new[] { typeof(string), typeof(DateTime), typeof(Enum), typeof(decimal), typeof(Guid), }; #endregion Private Fields #region .ToXml /// <summary> /// Converts an anonymous type to an XElement. /// </summary> /// <param name="input">The input.</param> /// <returns>Returns the object as it's XML representation in an XElement.</returns> public static XElement ToXml(this object input) { return input.ToXml(null); } /// <summary> /// Converts an anonymous type to an XElement. /// </summary> /// <param name="input">The input.</param> /// <param name="element">The element name.</param> /// <returns>Returns the object as it's XML representation in an XElement.</returns> public static XElement ToXml(this object input, string element) { return _ToXml(input, element); } private static XElement _ToXml(object input, string element, int? arrayIndex = null, string arrayName = null) { if (input == null) return null; if (String.IsNullOrEmpty(element)) { string name = input.GetType().Name; element = name.Contains("AnonymousType") ? "Object" : arrayIndex != null ? arrayName + "_" + arrayIndex : name; } element = XmlConvert.EncodeName(element); var ret = new XElement(element); if (input != null) { var type = input.GetType(); var props = type.GetProperties(); var elements = props.Select(p => { var pType = Nullable.GetUnderlyingType(p.PropertyType) ?? p.PropertyType; var name = XmlConvert.EncodeName(p.Name); var val = pType.IsArray ? "array" : p.GetValue(input, null); var value = pType.IsArray ? GetArrayElement(p, (Array)p.GetValue(input, null)) : pType.IsSimpleType() || pType.IsEnum ? new XElement(name, val) : val.ToXml(name); return value; }) .Where(v=>v !=null); ret.Add(elements); } return ret; } #region helpers /// <summary> /// Gets the array element. /// </summary> /// <param name="info">The property info.</param> /// <param name="input">The input object.</param> /// <returns>Returns an XElement with the array collection as child elements.</returns> private static XElement GetArrayElement(PropertyInfo info, Array input) { var name = XmlConvert.EncodeName(info.Name); XElement rootElement = new XElement(name); var arrayCount = input == null ? 0 : input.GetLength(0); for (int i = 0; i < arrayCount; i++) { var val = input.GetValue(i); XElement childElement = val.GetType().IsSimpleType() ? new XElement(name + "_" + i, val) : _ToXml(val, null, i, name); rootElement.Add(childElement); } return rootElement; } #region .IsSimpleType public static bool IsSimpleType(this Type type) { return type.IsPrimitive || WriteTypes.Contains(type); } #endregion .IsSimpleType #endregion helpers #endregion .ToXml }
我自己的版本,然后出色的工作@Matthew和@Martin:枚举数组现在支持和数组的概念一般化为IEnumerable,以支持所有types的集合。
public static class ObjectExtensions { /// <summary> /// Converts an anonymous type to an XElement. /// </summary> /// <param name="input">The input.</param> /// <returns>Returns the object as it's XML representation in an XElement.</returns> public static XElement ToXml2(this object input) { return input.ToXml2(null); } /// <summary> /// Converts an anonymous type to an XElement. /// </summary> /// <param name="input">The input.</param> /// <param name="element">The element name.</param> /// <returns>Returns the object as it's XML representation in an XElement.</returns> public static XElement ToXml2(this object input, string element) { return _ToXml(input, element); } private static XElement _ToXml(object input, string element, int? arrayIndex = null, string arrayName = null) { if (input == null) return null; if (String.IsNullOrEmpty(element)) { string name = input.GetType().Name; element = name.Contains("AnonymousType") ? "Object" : arrayIndex != null ? arrayName + "_" + arrayIndex : name; } element = XmlConvert.EncodeName(element); var ret = new XElement(element); if (input != null) { var type = input.GetType(); var props = type.GetProperties(); var elements = props.Select(p => { var pType = Nullable.GetUnderlyingType(p.PropertyType) ?? p.PropertyType; var name = XmlConvert.EncodeName(p.Name); var val = pType.IsArray ? "array" : p.GetValue(input, null); var value = pType.IsEnumerable() ? GetEnumerableElements(p, (IEnumerable)p.GetValue(input, null)) : pType.IsSimpleType2() || pType.IsEnum ? new XElement(name, val) : val.ToXml2(name); return value; }) .Where(v=>v !=null); ret.Add(elements); } return ret; } #region helpers private static XElement GetEnumerableElements(PropertyInfo info, IEnumerable input) { var name = XmlConvert.EncodeName(info.Name); XElement rootElement = new XElement(name); int i = 0; foreach(var v in input) { XElement childElement = v.GetType().IsSimpleType2() || v.GetType().IsEnum ? new XElement(name + "_" + i, v) : _ToXml(v, null, i, name); rootElement.Add(childElement); i++; } return rootElement; } private static readonly Type[] WriteTypes = new[] { typeof(string), typeof(DateTime), typeof(Enum), typeof(decimal), typeof(Guid), }; public static bool IsSimpleType2(this Type type) { return type.IsPrimitive || WriteTypes.Contains(type); } private static readonly Type[] FlatternTypes = new[] { typeof(string) }; public static bool IsEnumerable(this Type type) { return typeof(IEnumerable).IsAssignableFrom(type) && !FlatternTypes.Contains(type); } #endregion }
下面的答案以我需要的方式处理IEnumerables,并将转向此:
new { Foo = new[] { new { Name = "One" }, new { Name = "Two" }, }, Bar = new[] { new { Name = "Three" }, new { Name = "Four" }, }, }
进入这个:
<object> <Foo><Name>One</Name></Foo> <Foo><Name>Two</Name></Foo> <Bar><Name>Three</Name></Bar> <Bar><Name>Four</Name></Bar> </object>
所以在这里,马修的另一个答案是:
public static class Tools { private static readonly Type[] WriteTypes = new[] { typeof(string), typeof(Enum), typeof(DateTime), typeof(DateTime?), typeof(DateTimeOffset), typeof(DateTimeOffset?), typeof(int), typeof(int?), typeof(decimal), typeof(decimal?), typeof(Guid), typeof(Guid?), }; public static bool IsSimpleType(this Type type) { return type.IsPrimitive || WriteTypes.Contains(type); } public static object ToXml(this object input) { return input.ToXml(null); } public static object ToXml(this object input, string element) { if (input == null) return null; if (string.IsNullOrEmpty(element)) element = "object"; element = XmlConvert.EncodeName(element); var ret = new XElement(element); if (input != null) { var type = input.GetType(); if (input is IEnumerable && !type.IsSimpleType()) { var elements = (input as IEnumerable<object>) .Select(m => m.ToXml(element)) .ToArray(); return elements; } else { var props = type.GetProperties(); var elements = from prop in props let name = XmlConvert.EncodeName(prop.Name) let val = prop.GetValue(input, null) let value = prop.PropertyType.IsSimpleType() ? new XElement(name, val) : val.ToXml(name) where value != null select value; ret.Add(elements); } } return ret; } }