2010-03-22 97 views
12

我試圖用System.Xml.Serialization.XmlSerializer序列化動態加載(和編譯後的類)。如果我將有問題的類構建到主程序集中,那麼一切都按預期工作。但是,如果我從動態加載的程序集編譯並加載類,則XmlSerializer會引發異常。XmlSerializer在序列化動態加載類型時拋出異常

我在做什麼錯?

我創建了下面的.NET 3.5 C#應用程序來重現問題:

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

產生以下輸出:

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

編輯:去掉了一些多餘的引用程序

+2

+1提供代碼複製問題。 – 2010-03-22 12:43:49

回答

7

更改CompilerParameters.GenerateInMemoryfalse它會工作。我不知道這是否是XML序列化過程的限制,但如果將程序集生成到磁盤上的臨時位置不是問題,那麼這將解決您的問題。

+0

確實,這工作。還沒有接受答案,因爲我想知道_why_發生了這種情況。 – anorm 2010-03-22 13:04:32

+0

@Dr。 Sbaitso,我也很好奇爲什麼。您可以在connect.microsoft.com中提交問題以獲得官方解釋。 – 2010-03-22 15:32:26

+3

用戶[cronos](http://stackoverflow.com/users/711977/cronos)發佈了以下內容,但它被刪除了:「CompilerParameters.GenerateInMemory = false」的原因是程序集必須在磁盤上持久化。這是因爲用於編譯動態創建的XML序列化類型的C#編譯器必須能夠引用它。編譯器在單獨的(子)進程中運行,並且不能在內存中引用程序集。 – 2011-05-20 21:49:21

1

RE:更改CompilerParameters.GenerateInMemory假

又是怎樣做呢?

相關問題