NOTA: He entrado en muchos detalles sobre el JavaScriptSerializer al comienzo de mi respuesta, si solo quiere leer sobre la resolución del problema de tipo conocido mencionado en la pregunta original, salte hasta el final de la respuesta.
Rendimiento
Sobre la base de la benchmarks corría, el JavaScriptSerializer es el mucho más lento que las otras alternativas y puede tomar 2 veces el tiempo para serializar/deserializar un objeto en comparación con DataContractSerializer.
No hay necesidad de un tipo conocido
Dicho esto, el JavaScriptSerializer es más flexible ya que no requiere especificar los tipos conocidos '' antes de tiempo, y el JSON serializado es más limpio, al menos en el caso de los diccionarios (véanse los ejemplos here).
La otra cara de esa flexibilidad en torno a los tipos conocidos es que no podrá deserializar la misma cadena JSON al tipo original.Por ejemplo, supongamos que tengo una clase simple Person
:
public class Person
{
public string Name { get; set; }
public int Age { get; set; }
}
Y si puedo crear una instancia de Dictinoary<string, object>
y añadir una instancia de la clase Person
a ella antes de que la serialización:
var dictionary = new Dictionary<string, object>();
dictionary.Add("me", new Person { Name = "Yan", Age = 30 });
var serializer = new new JavaScriptSerializer();
var json = serializer .Serialize(dictionary);
Voy Obtenga el siguiente JSON {"me":{"Name":"Yan","Age":30}}
que es muy limpio pero no contiene ningún tipo de información. Así supuesta si tiene dos clases con las mismas definiciones de miembros o si Person
es una subclase sin introducir cualquier miembro adicional:
public class Employee : Person
{
}
entonces simplemente no hay manera para que el serializador para poder garantizar que el JSON {"Name":"Yan","Age":30}
se puede deserializar al tipo correcto.
Si deserializar {"me":{"Name":"Yan","Age":30}}
utilizando el JavaScriptSerializer, en el diccionario que vuelva el valor asociado con el "yo" no es una instancia de Person
sino un Dictionary<string, object>
lugar, una bolsa de propiedades simple.
Si desea obtener una instancia Person
atrás, usted podría (aunque lo más probable es que nunca quiere!) Convertir ese Dictionary<string, object>
utilizando el método ConvertToType
ayudante:
var clone = serializer.Deserialize<Dictionary<string, object>>(json);
var personClone = serializer.ConverToType<Person>(clone["me"]);
Por otro lado, si no necesita preocuparse por deserializar esos JSON en el tipo correcto y la serialización JSON no es un cuello de botella de rendimiento (perfile su código y descubra cuánto tiempo de CPU se gasta en serialización si aún no lo ha hecho) entonces diría solo use JavaScriptSerializer.
La inyección de tipo conocido
si, al final del día, usted todavía tiene que utilizar DataContractSerializer y la necesidad de inyectar esos KnownTypes, aquí hay dos cosas que puede probar.
1) Pase la matriz de tipos conocidos al DataContractSerializer constructor.
2) Pase una subclase de DataContractResolver (con los medios para localizar los tipos de interés) a DataContractSerializer constructor
Se puede crear un 'registro de tipo conocido' del tipo que realiza un seguimiento de los tipos que se puede ser agregado al diccionario, y si el control de todos los tipos que usted necesita inyectarse a DataContractSerializer, puede intentar lo más sencillo:
crear una clase con métodos estáticos KnownTypeRegister
añadir un tipo de a la lista de tipos conocidos:
public static class KnownTypeRegister
{
private static readonly ConcurrentBag _knownTypes = new ConcurrentBag();
public static void Add(Type type)
{
_knownTypes.Add(type);
}
public static IEnumerable Get()
{
return _knownTypes.ToArray();
}
}
Añadir un constructor estático que registra los tipos con el registro:
[DataContract]
public class Person
{
static Person()
{
KnownTypeRegister.Add(typeof(Person));
}
[DataMember]
public string Name { get; set; }
[DataMember]
public int Age { get; set; }
}
Obtener la matriz de tipos conocidos del registro cuando se construye el serializador:
var serializer = new DataContractSerializer(typeof(Dictionary<string, object>), KnownTypeRegister.Get());
Más opciones dinámicas/mejores son posibles e, pero también son más difíciles de implementar, si desea obtener más información sobre la resolución dinámica conocida, consulte el artículo de MSDN de Juval Lowy sobre el tema here. Además, this blog post de Carlos Figueira también entra en detalles sobre técnicas más avanzadas, tales como la generación dinámica de los tipos, ¡vale la pena leerlos mientras habla sobre el tema!
Me alegra que la gente ya esté así. Por favor, no se moleste en responder con argumentos sobre cómo WCF no fue hecho para eso, etc. Le agradecería si simplemente nos puede informar si hay una manera conocida o si usted ha estado allí y se dio por vencido por razones válidas (qué ¿razones?). – tishma