【问题标题】:XmlSerializer won't serialize IEnumerableXmlSerializer 不会序列化 IEnumerable
【发布时间】:2012-02-24 12:16:41
【问题描述】:

我有一个调用记录器,旨在记录所有方法调用以及与使用 XmlSerializer 的方法关联的参数。它适用于大多数调用,但它会为所有具有IEnumerable 类型参数的方法抛出异常。

例如,void MethodWithPlace( Place value ) 将被序列化,但 void MethodWithPlace( IEnumerable<Place> value ) 不会。

例外是

System.NotSupportedException:无法序列化接口 System.Collections.Generic.IEnumerable`1[[地点, 测试,版本=0.0.0.0,文化=中性]]。

我应该怎么做才能使其与IEnumerable 作为其参数之一的那些方法一起工作?

【问题讨论】:

标签: c# xml-serialization xmlserializer


【解决方案1】:

序列化 IEnumerable 属性的方式是使用代理属性

[XmlRoot]
public class Entity {
   [XmlIgnore]
   public IEnumerable<Foo> Foo { get; set; }

   [XmlElement, Browsable(false), EditorBrowsable(EditorBrowsableState.Never)]
   public List<Foo> FooSurrogate { get { return Foo.ToList(); } set { Foo = value; } }
}

它很丑,但它可以完成工作。更好的解决方案是编写一个代理类(即EntitySurrogate)。

【讨论】:

  • 在代理上投掷[Browsable(false), EditorBrowsable(EditorBrowsableState.Never)] 将有助于隐藏它。此外,可能需要考虑 ShouldSerialize* 模式。 Similar to this answer.
【解决方案2】:

XmlSerializer 基本上不能序列化接口。那么,解决方案是给它一个具体的实例来序列化。根据您的调用记录器的工作方式,我会考虑使用

var serializer = new XmlSerializer(value.GetType());

【讨论】:

  • 我们所做的是获取一个类中所有可能的方法参数,并将它们作为extraTypes放入XmlSerializer的构造函数中。然后,我们为该类创建一个透明代理,捕获方法调用,序列化它们,并调用真正的方法..
【解决方案3】:

我认为您无法将其序列化。尝试将 IEnumerable 转换为 List,然后就可以序列化了。

【讨论】:

  • 由于我无法更改方法签名,是否有任何解决方法可以解决此问题?
  • 如果您只是将 .ToList() 添加到该方法签名中,或者我应该说让它返回 IEnumberable.ToList()
  • 你可以使用不同的序列化器,比如 NetDataContractSerializer 吗?您将无法使用 XML 序列化程序来执行此操作。
  • 您必须使用不同的序列化程序。例如,有人传递了一个继承自 IEnumerable 的不可序列化参数。 XML 序列化程序将无法处理它。
  • 我认为您是说您不能修改正在记录的方法,因此您无法控制 IEnumerable 是否是正在记录的方法中的参数,对吗?那么,您是否可以在尝试序列化之前修改尝试序列化此数据并更改任何 IEnumerable 对象的代码,方法是在序列化尝试之前对其使用 .ToList() 方法?或者,您能否将日志记录传递给一个中间人类,该类可以将任何 IEnumerables 转换为列表,然后再将其传递给序列化器?否则,我认为您需要按照 DJ KRAZE 的建议修改方法签名。
【解决方案4】:

要实现 XML 可序列化,从 IEnumerable 继承的类型必须在其继承层次结构的所有级别上都有 Add(System.Object) 的实现。 {your class} 没有实现 Add(System.Object)。

实现 Add() 函数,你可能会解决问题

【讨论】:

    【解决方案5】:

    XmlSerializer 不支持这个。尝试YAXLib 进行这些类型的序列化。

    【讨论】:

    【解决方案6】:

    也许不是最好的方法,但它对我有用。 我创建了一个进行序列化的方法。

    使用

    var xml = Util.ObjetoToXML(obj, null, null).OuterXml;

    方法

            public static XmlDocument ObjetoToXML(object obj, XmlDocument xmlDocument, XmlNode rootNode)
        {
    
            if (xmlDocument == null)
                xmlDocument = new XmlDocument();
    
            if (obj == null) return xmlDocument;
    
            Type type = obj.GetType();
    
            if (rootNode == null) { 
                rootNode = xmlDocument.CreateElement(string.Empty, type.Name, string.Empty);
                xmlDocument.AppendChild(rootNode);
            }
    
            if (type.IsPrimitive || type == typeof(Decimal) || type == typeof(String) || type == typeof(DateTime))
            {
    
                // Simples types
                if (obj != null)
                    rootNode.InnerText = obj.ToString();
    
            }
            else if (type.IsGenericType && type.GetGenericTypeDefinition() == typeof(List<>))
            {
                // Genericis types
    
                XmlNode node = null;
    
                foreach (var item in (IEnumerable)obj)
                {
                    if (node == null)
                    {
                        node = xmlDocument.CreateElement(string.Empty, item.GetType().Name, string.Empty);
                        node = rootNode.AppendChild(node);
                    }
    
    
                    ObjetoToXML(item, xmlDocument, node);
                }
    
            }
            else
            {
    
                // Classes types
                foreach (var propertie in obj.GetType().GetProperties())
                {
    
                    XmlNode node = xmlDocument.CreateElement(string.Empty, propertie.Name, string.Empty);
                    node = rootNode.AppendChild(node);
                    var valor = propertie.GetValue(obj, null);
    
                    ObjetoToXML(valor, xmlDocument, node);
                }
    
            }
    
    
            return xmlDocument;
    
        }
    

    【讨论】:

      【解决方案7】:

      你可以使用 DataContractSerializer

              using (var ms = new MemoryStream())
              {
                  var serialiser = new DataContractSerializer(typeof (EnvironmentMetadata));
                  serialiser.WriteObject(ms, environmentMetadata);
      
                  var s = Encoding.ASCII.GetString(ms.ToArray());
                  return s;
              }
      

      【讨论】:

      • 问题是关于 XML 序列化程序,而不是数据协定序列化程序。
      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2023-04-05
      • 1970-01-01
      • 1970-01-01
      • 2015-02-10
      • 2010-12-06
      相关资源
      最近更新 更多