2010-03-22 21 views
12

Estoy tratando de usar el System.Xml.Serialization.XmlSerializer para serializar una clase cargada dinámicamente (y compilada). Si construyo la clase en cuestión en el ensamblaje principal, todo funciona como se espera. Pero si compilo y cargo la clase desde un ensamblaje cargado dinámicamente, el XmlSerializer arroja una excepción.XmlSerializer arroja una excepción al serializar el tipo cargado dinámicamente

¿Qué estoy haciendo mal?

He creado la siguiente # aplicación .NET 3.5 C para reproducir el problema:

using System; 
using System.Collections.Generic; 
using System.Xml.Serialization; 
using System.Text; 
using System.Reflection; 
using System.CodeDom.Compiler; 
using Microsoft.CSharp; 

public class StaticallyBuiltClass 
{ 
    public class Item 
    { 
     public string Name { get; set; } 
     public int Value { get; set; } 
    } 
    private List<Item> values = new List<Item>(); 
    public List<Item> Values { get { return values; } set { values = value; } } 
} 

static class Program 
{ 
    static void Main() 
    { 
     RunStaticTest(); 
     RunDynamicTest(); 
    } 

    static void RunStaticTest() 
    { 
     Console.WriteLine("-------------------------------------"); 
     Console.WriteLine(" Serializing StaticallyBuiltClass..."); 
     Console.WriteLine("-------------------------------------"); 
     var stat = new StaticallyBuiltClass(); 

     Serialize(stat.GetType(), stat); 

     Console.WriteLine(); 
    } 

    static void RunDynamicTest() 
    { 
     Console.WriteLine("-------------------------------------"); 
     Console.WriteLine(" Serializing DynamicallyBuiltClass..."); 
     Console.WriteLine("-------------------------------------"); 
     CSharpCodeProvider csProvider = new CSharpCodeProvider(new Dictionary<string, string> { { "CompilerVersion", "v3.5" } }); 

     CompilerParameters csParams = new System.CodeDom.Compiler.CompilerParameters(); 
     csParams.GenerateInMemory = true; 
     csParams.GenerateExecutable = false; 
     csParams.ReferencedAssemblies.Add("System.dll"); 
     csParams.CompilerOptions = "/target:library"; 

     StringBuilder classDef = new StringBuilder(); 
     classDef.AppendLine("using System;"); 
     classDef.AppendLine("using System.Collections.Generic;"); 
     classDef.AppendLine(""); 
     classDef.AppendLine("public class DynamicallyBuiltClass"); 
     classDef.AppendLine("{"); 
     classDef.AppendLine(" public class Item"); 
     classDef.AppendLine(" {"); 
     classDef.AppendLine("  public string Name { get; set; }"); 
     classDef.AppendLine("  public int Value { get; set; }"); 
     classDef.AppendLine(" }"); 
     classDef.AppendLine(" private List<Item> values = new List<Item>();"); 
     classDef.AppendLine(" public List<Item> Values { get { return values; } set { values = value; } }"); 
     classDef.AppendLine("}"); 

     CompilerResults res = csProvider.CompileAssemblyFromSource(csParams, new string[] { classDef.ToString() }); 

     foreach (var line in res.Output) 
     { 
      Console.WriteLine(line); 
     } 

     Assembly asm = res.CompiledAssembly; 
     if (asm != null) 
     { 
      Type t = asm.GetType("DynamicallyBuiltClass"); 
      object o = t.InvokeMember("", BindingFlags.CreateInstance, null, null, null); 
      Serialize(t, o); 
     } 

     Console.WriteLine(); 
    } 

    static void Serialize(Type type, object o) 
    { 
     var serializer = new XmlSerializer(type); 
     try 
     { 
      serializer.Serialize(Console.Out, o); 
     } 
     catch(Exception ex) 
     { 
      Console.WriteLine("Exception caught while serializing " + type.ToString()); 
      Exception e = ex; 
      while (e != null) 
      { 
       Console.WriteLine(e.Message); 
       e = e.InnerException; 
       Console.Write("Inner: "); 
      } 
      Console.WriteLine("null"); 
      Console.WriteLine(); 
      Console.WriteLine("Stack trace:"); 
      Console.WriteLine(ex.StackTrace); 
     } 
    } 
} 

que genera el siguiente resultado:

------------------------------------- 
Serializing StaticallyBuiltClass... 
------------------------------------- 
<?xml version="1.0" encoding="IBM437"?> 
<StaticallyBuiltClass xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:xsd="http://www.w3.org/2001/XMLSchema"> 
    <Values /> 
</StaticallyBuiltClass> 
------------------------------------- 
Serializing DynamicallyBuiltClass... 
------------------------------------- 
Exception caught while serializing DynamicallyBuiltClass 
There was an error generating the XML document. 
Inner: The type initializer for 'Microsoft.Xml.Serialization.GeneratedAssembly.XmlSerializationWriterDynamicallyBuiltClass' threw an exception. 
Inner: Object reference not set to an instance of an object. 
Inner: null 

Stack trace: 
    at System.Xml.Serialization.XmlSerializer.Serialize(XmlWriter xmlWriter, Object o, XmlSerializerNamespaces namespaces, String encodingStyle, String id) 
    at System.Xml.Serialization.XmlSerializer.Serialize(TextWriter textWriter, Object o, XmlSerializerNamespaces namespaces) 
    at System.Xml.Serialization.XmlSerializer.Serialize(TextWriter textWriter, Object o) 
    at Program.Serialize(Type type, Object o) in c:\dev\SerTest\SerTest\Program.cs:line 100 

Editar: Se ha eliminado algunos ensamblados de referencia extraños

+2

+1 para proporcionar el código replica el problema. –

Respuesta

7

Cambie CompilerParameters.GenerateInMemory a false y funcionará. No sé si esto es una limitación del proceso de serialización XML, pero si no es un problema generar el ensamblado en una ubicación temporal en el disco, entonces esto resolverá su problema.

+0

De hecho, esto funcionó. Aún no he aceptado la respuesta, ya que me gustaría saber por qué sucede esto. – anorm

+0

@Dr. Sbaitso, también tengo curiosidad sobre el por qué. Puede enviar un problema en connect.microsoft.com para obtener una explicación oficial. –

+3

El usuario [cronos] (http://stackoverflow.com/users/711977/cronos) publicó lo siguiente, pero se eliminó: El motivo por el que "CompilerParameters.GenerateInMemory = false" funciona es que el ensamblado debe ser persistente en el disco . Esto se debe a que el compilador de C# utilizado para compilar los tipos de serialización XML creados dinámicamente debe poder hacer referencia a él. El compilador se ejecuta en un proceso separado (secundario) y no puede hacer referencia a un ensamblaje en la memoria. –

1

RE: Cambio CompilerParameters.GenerateInMemory en false

Y cómo se hace eso?

Cuestiones relacionadas