2012-02-01 95 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; 

    }