2012-02-01 99 views
31

我有一个调用记录器,旨在记录所有方法调用以及与使用XmlSerializer的方法关联的参数。它适用于大多数调用,但对于参数为IEnumerable类型的所有方法都会引发异常。XmlSerializer不会序列化IEnumerable

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

唯一的例外是

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

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

+2

你可以用一个具体实现IEnumerable的,如清单更换方法定义? – 2012-02-01 19:51:39

+0

[使用WCF,LINQ,JSON时无法序列化'System.Linq.Enumerable ...'类型的参数的可能的重复](http://stackoverflow.com/questions/2068897/cannot-serialize-parameter-of-type -system-linq-enumerable-when-using-wcf) – Coincoin 2012-02-01 19:52:33

+0

[Serialize Objects using xmlSerializer。序列化和IEnumerable对象](http://stackoverflow.com/questions/2729875/serialize-objects-using-xmlserializer-serialize-and-ienumerable-objects) – 2012-02-01 19:52:47

回答

9

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

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

我们所做的是在类中获取所有可能的方法参数,并将它们作为extraTypes放入XmlSerializer的构造函数中。然后,我们为该类创建透明代理,捕获方法调用,序列化它们,并调用真实的方法。 – uni 2012-02-01 20:08:29

8

我不认为你能够序列化。尝试将IEnumerable转换为List,然后您将能够序列化。

+2

由于我无法更改方法签名,是否有解决此问题的解决方法? – uni 2012-02-01 20:02:47

+2

如果您只是将.ToList()添加到该方法签名或者我应该说让它返回IEnumberable.ToList() – MethodMan 2012-02-01 20:04:19

+2

您可以使用不同的序列化程序,如NetDataContractSerializer?您将无法使用XML序列化程序执行此操作。 – Joe 2012-02-01 20:04:29

-1

XmlSerializer不支持这一点。尝试YAXLib这些类型的序列化。

26

你序列化一个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)。

+1

在代理上抛出'[Browsable(false),EditorBrowsable(EditorBrowsableState.Never)]'将有助于隐藏它。另外,可能要考虑ShouldSerialize *模式。 [类似于这个答案](http://stackoverflow.com/a/10840603/425809)。 – Richard 2013-06-18 16:33:18

3

要成为可串行化的XML,从IEnumerable继承的类型必须在它们的继承层次结构的所有级别都有一个Add(System.Object)实现。 {你的类}不实现Add(System.Object)。

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

-1

可以使用的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; 
     } 
+2

问题是关于XML序列化程序,而不是数据协定序列化程序。 – 2015-01-14 15:40:49

0

也许不是最好的方式,但它为我工作。 我创建了一个序列化的方法。

使用

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; 

    }