2011-10-01 24 views
6

Estoy usando DataContractSerializer para serializar un objeto que contiene un miembro Dictionary<string,object>, que está marcado con [DataMember()]. La idea es tener una bolsa flexible de atributos de objeto, y no sé cuáles podrían ser esos atributos.DataContractSerializer y Dictionary <string, object> falla al leer

Esto funciona muy bien cuando estoy poniendo int, double y string objetos en el diccionario, pero cuando pongo un List<string> en ella no puede deserializar el objeto con:

System.InvalidOperationException: Node type Element is not supported in this operation. 

El diccionario entero es serializado a XML, y parece bastante razonable:

<Attributes xmlns:d2p1="http://schemas.microsoft.com/2003/10/Serialization/Arrays"> 
    <d2p1:KeyValueOfstringanyType> 
     <d2p1:Key>name</d2p1:Key> 
     <d2p1:Value xmlns:d4p1="http://www.w3.org/2001/XMLSchema" i:type="d4p1:string">Test object</d2p1:Value> 
    </d2p1:KeyValueOfstringanyType> 
    <d2p1:KeyValueOfstringanyType> 
     <d2p1:Key>x</d2p1:Key> 
     <d2p1:Value xmlns:d4p1="http://www.w3.org/2001/XMLSchema" i:type="d4p1:double">0.5</d2p1:Value> 
    </d2p1:KeyValueOfstringanyType> 
    <d2p1:KeyValueOfstringanyType> 
     <d2p1:Key>y</d2p1:Key> 
     <d2p1:Value xmlns:d4p1="http://www.w3.org/2001/XMLSchema" i:type="d4p1:double">1.25</d2p1:Value> 
    </d2p1:KeyValueOfstringanyType> 
    <d2p1:KeyValueOfstringanyType> 
     <d2p1:Key>age</d2p1:Key> 
     <d2p1:Value xmlns:d4p1="http://www.w3.org/2001/XMLSchema" i:type="d4p1:int">4</d2p1:Value> 
    </d2p1:KeyValueOfstringanyType> 
    <d2p1:KeyValueOfstringanyType> 
     <d2p1:Key>list-of-strings</d2p1:Key> 
     <d2p1:Value> 
      <d2p1:string>one string</d2p1:string> 
      <d2p1:string>two string</d2p1:string> 
      <d2p1:string>last string</d2p1:string> 
     </d2p1:Value> 
    </d2p1:KeyValueOfstringanyType> 
</Attributes> 

Nota del list-of-strings al final allí. Tiene todos los valores pero nada que indique que es List<string> o lo que sea.

¿Cuál es la forma correcta de manejar esta situación?

Respuesta

8

Intente utilizar el KnownTypeAttribute para que DataContractSerializer conozca el tipo List<string>. Desafortunadamente, eso parece ir en contra de tu idea de no tener que saber sobre los tipos anteriores.

Estoy basando esto en el siguiente código, que utiliza DataContractSerializer para serializar un Dictionary<string, object> contiene List<string>:

Dictionary<string,object> dictionary = new Dictionary<string, object>(); 

dictionary.Add("k1", new List<string> { "L1", "L2", "L3" }); 

List<Type> knownTypes = new List<Type> { typeof(List<string>) }; 
DataContractSerializer serializer = new DataContractSerializer(typeof(Dictionary<string,object>), knownTypes); 
MemoryStream stream = new MemoryStream(); 

serializer.WriteObject(stream, dictionary); 

StreamReader reader = new StreamReader(stream); 

stream.Position = 0; 
string xml = reader.ReadToEnd(); 

Si knownTypes no se proporciona a la DataContractSerializer, se produce una excepción.

SerializationException: Tipo 'System.Collections.Generic.List`1 [[System.String mscorlib versión = 4.0.0.0, Culture = neutral, PublicKeyToken = b77a5c561934e089]]' con nombre de contrato de datos 'ArrayOfstring: http: //schemas.microsoft.com/2003/10/Serialization/Arrays' no se espera. Considere el uso de un DataContractResolver o agregue cualquier tipo de no conocido de forma estática a la lista de tipos conocidos, por ejemplo, mediante el uso del atributo KnownTypeAttribute o agregándolos a la lista de tipos conocidos pasados ​​a DataContractSerializer.

0

WCF no tiene manera de saber que lo que tienes es un List<string> allí - notar que todos los demás elementos <Value> tienen un "tipo de pista" (la i: tipo de atributo). Si desea deserializarlo, necesita tener la marca, y también debe decirle a WCF que List<string> es un "tipo conocido" - ver a continuación. Para obtener más información sobre tipos conocidos (y por qué son necesarios), hay manygoodresources en el web.

public class StackOverflow_7620718 
{ 
    public static void Test() 
    { 
     Dictionary<string, object> dict = new Dictionary<string, object> 
     { 
      { "name", "Test object" }, 
      { "x", 0.5 }, 
      { "y", 1.25 }, 
      { "age", 4 }, 
      { "list-of-strings", new List<string> { "one string", "two string", "last string" } } 
     }; 
     MemoryStream ms = new MemoryStream(); 
     XmlWriter w = XmlWriter.Create(ms, new XmlWriterSettings 
     { 
      Indent = true, 
      Encoding = new UTF8Encoding(false), 
      IndentChars = " ", 
      OmitXmlDeclaration = true, 
     }); 
     DataContractSerializer dcs = new DataContractSerializer(dict.GetType(), new Type[] { typeof(List<string>) }); 
     dcs.WriteObject(w, dict); 
     w.Flush(); 
     Console.WriteLine(Encoding.UTF8.GetString(ms.ToArray())); 
     ms.Position = 0; 
     Console.WriteLine("Now deserializing it:"); 
     Dictionary<string, object> dict2 = (Dictionary<string, object>)dcs.ReadObject(ms); 
     foreach (var key in dict2.Keys) 
     { 
      Console.WriteLine("{0}: {1}", key, dict2[key].GetType().Name); 
     } 
    } 
} 
Cuestiones relacionadas