tipo serializar reflejar net error deserializar c# xml oop serialization xml-serialization

c# - serializar - error al reflejar el tipo vb net



¿Cómo puedo serializar las clases internas usando XmlSerializer? (5)

Como alternativa, puede usar clases públicas creadas dinámicamente (que no estarán expuestas a terceros):

static void Main() { var emailType = CreateEmailType(); dynamic email = Activator.CreateInstance(emailType); email.From = "[email protected]"; email.To = "[email protected]"; email.Subject = "Dynamic Type"; email.Boby = "XmlSerializer can use this!"; } static Type CreateEmailType() { var assemblyName = new AssemblyName("DynamicAssembly"); var assemblyBuilder = AppDomain.CurrentDomain.DefineDynamicAssembly(assemblyName, AssemblyBuilderAccess.Run); var moduleBuilder = assemblyBuilder.DefineDynamicModule(assemblyName.Name); var typeBuilder = moduleBuilder.DefineType( "Email", ( TypeAttributes.Public | TypeAttributes.Sealed | TypeAttributes.SequentialLayout | TypeAttributes.Serializable ), typeof(ValueType) ); typeBuilder.DefineField("From", typeof(string), FieldAttributes.Public); typeBuilder.DefineField("To", typeof(string), FieldAttributes.Public); typeBuilder.DefineField("Subject", typeof(string), FieldAttributes.Public); typeBuilder.DefineField("Body", typeof(string), FieldAttributes.Public); return typeBuilder.CreateType(); }

Estoy construyendo una biblioteca para interactuar con un tercero. La comunicación es a través de publicaciones XML y HTTP. Eso está funcionando.

Pero, cualquiera sea el código que use la biblioteca, no necesita conocer las clases internas. Mis objetos internos se serializan a XML utilizando este método:

internal static string SerializeXML(Object obj) { XmlSerializer serializer = new XmlSerializer(obj.GetType(), "some.domain"); //settings XmlWriterSettings settings = new XmlWriterSettings(); settings.Indent = true; settings.OmitXmlDeclaration = true; using (StringWriter stream = new StringWriter()) { using (XmlWriter writer = XmlWriter.Create(stream, settings)) { serializer.Serialize(writer, obj); } return stream.ToString(); } }

Sin embargo, cuando cambio el modificador de acceso de mis clases a internal , obtengo una excepción en tiempo de ejecución :

[System.InvalidOperationException] = {"MyNamespace.MyClass es inaccesible debido a su nivel de protección. Solo se pueden procesar los tipos públicos."}

Esa excepción ocurre en la primera línea del código de arriba.

Me gustaría que las clases de mi biblioteca no sean públicas porque no quiero exponerlas. ¿Puedo hacer eso? ¿Cómo puedo hacer que los tipos internos sean serializables, usando mi serializador genérico? ¿Qué estoy haciendo mal?


Del blog de Sowmy Srinivasan: serialización de tipos internos utilizando XmlSerializer :

Ser capaz de serializar tipos internos es una de las solicitudes más comunes vistas por el equipo de XmlSerializer . Es una solicitud razonable de personas que envían bibliotecas. No quieren hacer públicos los tipos de XmlSerializer solo por el serializador. Recientemente me mudé del equipo que escribió el XmlSerializer a un equipo que consume XmlSerializer. Cuando me encontré con una solicitud similar, dije: "De ninguna manera. Use DataContractSerializer ".

El motivo es simple XmlSerializer funciona generando código. El código generado vive en un ensamblaje generado dinámicamente y necesita acceder a los tipos que se serializan. Dado que XmlSerializer se desarrolló en un momento anterior al advenimiento de la generación de código liviano , el código generado no puede acceder a nada que no sean tipos públicos en otro ensamblado. Por lo tanto, los tipos que se serializan deben ser públicos.

Escucho a los lectores astutos susurrar "No tiene que ser público si se usa el atributo '' InternalsVisibleTo ''".

Digo: "Correcto, pero el nombre del conjunto generado no se conoce por adelantado. ¿A qué ensamblaje se puede ver el interior?"

Lectores astutos: "el nombre del ensamblado es conocido si se usa '' sgen.exe ''"

Yo: "Para que sgen genere un serializador para sus tipos, tienen que ser públicos"

Lectores astutos: "Podríamos hacer una compilación de dos pasos. Un pase para sgen con tipos como público y otro pase para envíos con tipos como internos".

¡Pueden estar en lo correcto! Si les pido a los lectores astutos que me escriban una muestra, probablemente escribirían algo como esto. (Descargo de responsabilidad: esta no es la solución oficial. YMMV)

using System; using System.IO; using System.Xml.Serialization; using System.Runtime.CompilerServices; using System.Reflection; [assembly: InternalsVisibleTo("Program.XmlSerializers")] namespace InternalTypesInXmlSerializer { class Program { static void Main(string[] args) { Address address = new Address(); address.Street = "One Microsoft Way"; address.City = "Redmond"; address.Zip = 98053; Order order = new Order(); order.BillTo = address; order.ShipTo = address; XmlSerializer xmlSerializer = GetSerializer(typeof(Order)); xmlSerializer.Serialize(Console.Out, order); } static XmlSerializer GetSerializer(Type type) { #if Pass1 return new XmlSerializer(type); #else Assembly serializersDll = Assembly.Load("Program.XmlSerializers"); Type xmlSerializerFactoryType = serializersDll.GetType("Microsoft.Xml.Serialization.GeneratedAssembly.XmlSerializerContract"); MethodInfo getSerializerMethod = xmlSerializerFactoryType.GetMethod("GetSerializer", BindingFlags.Public | BindingFlags.Instance); return (XmlSerializer)getSerializerMethod.Invoke(Activator.CreateInstance(xmlSerializerFactoryType), new object[] { type }); #endif } } #if Pass1 public class Address #else internal class Address #endif { public string Street; public string City; public int Zip; } #if Pass1 public class Order #else internal class Order #endif { public Address ShipTo; public Address BillTo; } }

Algunos astutos lectores de ''piratería'' pueden llegar a darme el build.cmd para compilarlo.

csc /d:Pass1 program.cs sgen program.exe csc program.cs


Esto puede ayudarte: MRB_ObjectSaver

Este proyecto te ayuda a guardar / cargar / clonar cualquier objeto en c # a / desde un archivo / cadena. En comparación con la "serialización de c #", este método mantiene la referencia a los objetos y el enlace entre los objetos no se romperá. (ver: SerializeObjectTest.cs para ver un ejemplo) Además, el tipo no se ha marcado como [Serializable]


También puede usar algo llamado xgenplus (http://xgenplus.codeplex.com/) esto genera el código que normalmente se ejecutará en el tiempo de ejecución. Luego, agregue eso a su solución y compílelo como parte de su solución. En ese punto, no importa si su objeto es interno: puede agregar el código generado previamente en el mismo espacio de nombres. El rendimiento de esto es increíblemente rápido, ya que todo está pregenerado.