2010-03-22 3 views
12

System.Xml.Serialization.XmlSerializer을 사용하여 동적으로로드 된 (및 컴파일 된 클래스)을 직렬화하려고합니다. 문제의 강좌를 주 어셈블리에 조립하면 모든 것이 예상대로 작동합니다. 그러나 동적으로로드 된 어셈블리에서 클래스를 컴파일하고로드하면 XmlSerializer에서 예외가 발생합니다.동적으로로드 된 형식을 직렬화 할 때 XmlSerializer가 예외를 throw합니다.

내가 뭘 잘못하고 있니?

나는 문제를 재현하려면 다음 .NET 3.5 C# 응용 프로그램 만들었습니다

------------------------------------- 
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 

편집 : 다음과 같은 출력을 생성

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); 
     } 
    } 
} 

제거 된 일부 외부 참조 된 어셈블리를

+2

+1 코드를 제공하면 문제가 복제됩니다. –

답변

7

CompilerParameters.GenerateInMemoryfalse으로 변경하면 제대로 작동합니다. 이것이 XML 직렬화 프로세스의 한계인지는 모르지만 디스크의 임시 위치에 어셈블리를 생성하는 것이 문제가 아니라면 문제가 해결됩니다.

+0

실제로 이것은 효과가있었습니다. 이 상황이 발생했는지 알고 싶으면 대답을 아직받지 못했습니다. – anorm

+0

@Dr. 스 베이트 소장님, 왜 그런지 궁금합니다. 공식적인 설명을 얻기 위해 connect.microsoft.com에서 문제를 제출할 수 있습니다. –

+3

사용자 [cronos] (http://stackoverflow.com/users/711977/cronos)에서 다음을 게시했지만 삭제되었습니다. "CompilerParameters.GenerateInMemory = false"가 작동하는 이유는 어셈블리가 디스크에서 지속적이어야한다는 것입니다 . 이는 동적으로 생성 된 XML serialization 형식을 컴파일하는 데 사용되는 C# 컴파일러가이를 참조 할 수 있어야하기 때문입니다. 컴파일러는 별도의 (자식) 프로세스에서 실행되며 메모리의 어셈블리를 참조 할 수 없습니다. –

1

RE : 변경 CompilerParameters.GenerateInMemory false로

그리고 어떻게 이루어집니다?

관련 문제