2010-03-22 35 views
12

Tôi đang cố gắng sử dụng System.Xml.Serialization.XmlSerializer để tuần tự hóa một lớp được nạp động (và được biên dịch). Nếu tôi xây dựng các lớp học trong câu hỏi vào lắp ráp chính, tất cả mọi thứ hoạt động như mong đợi. Nhưng nếu tôi biên dịch và tải lớp từ một assembly được nạp động, thì XmlSerializer sẽ ném một ngoại lệ.XmlSerializer ném ngoại lệ khi tuần tự nạp loại

Tôi đang làm gì sai?

tôi đã tạo ra các ứng dụng # .NET 3.5 C sau đây để tạo lại vấn đề:

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

mà tạo ra kết quả như sau:

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

Edit: Removed một số hội đồng tham chiếu không liên quan

+2

+1 để cung cấp mã sao chép sự cố. –

Trả lời

7

Thay đổi CompilerParameters.GenerateInMemory thành false và nó sẽ hoạt động. Tôi không biết nếu đây là một hạn chế của quá trình serialization XML, nhưng nếu nó không phải là một vấn đề cho bạn để tạo ra lắp ráp vào một vị trí tạm thời trên đĩa, sau đó điều này sẽ giải quyết vấn đề của bạn.

+0

Thật vậy, điều này đã hiệu quả. Chưa chấp nhận câu trả lời nhưng tôi muốn biết _why_ điều này xảy ra. – anorm

+0

@Dr. Sbaitso, tôi cũng tò mò về lý do tại sao. Bạn có thể gửi một vấn đề trong connect.microsoft.com để có được một lời giải thích chính thức. –

+3

Người dùng [cronos] (http://stackoverflow.com/users/711977/cronos) đăng bài sau đây, nhưng nó đã bị xóa: Lý do tại sao "CompilerParameters.GenerateInMemory = false" hoạt động là lắp ráp phải được liên tục trên đĩa . Điều này là do trình biên dịch C# được sử dụng để biên dịch các kiểu tuần tự hóa XML được tạo động phải có khả năng tham chiếu nó. Trình biên dịch chạy trong một tiến trình riêng biệt (con) và không thể tham chiếu một assembly trong bộ nhớ. –

1

RE: Thay đổi CompilerParameters.GenerateInMemory thành false

Và cách thực hiện?

Các vấn đề liên quan