序列化/反序列化动态对象

问题描述:

我有以下类别:序列化/反序列化动态对象

public abstract class Animal 
    { 
     public Animal() { _myType = getAnimal(this.GetType().Name); } 
     private dynamic _myType; 
     public dynamic myType { get { return _myType; } } 
    } 

    public class Cat : Animal 
    { 
     public Cat() : base() { } 
    } 

而其辅助功能:

public static T CreateAnimal<T>(string animal) 
    { 
     Type type = Type.GetType(typeof(Form1).FullName + "+" + animal); 
     return (T)Activator.CreateInstance(type); 
    } 
    public static dynamic getAnimal(string name) 
    { 
     dynamic theAnimal = Activator.CreateInstance(MyAnimals); // Will default to 'Cat' 
     FieldInfo fi = MyAnimals.GetField(name); 
     int iEnum = (int)fi.GetValue(MyAnimals); 
     return Enum.ToObject(MyAnimals, iEnum); 
    } 

因此获得了 '的myType' 从动态创建枚举 'MyAnimals':

public static Type MyAnimals; 

    public static void CreateAnimalEnum() 
    { 
     // Get the current application domain for the current thread. 
     AppDomain currentDomain = AppDomain.CurrentDomain; 

     // Create a dynamic assembly in the current application domain, 
     // and allow it to be executed and saved to disk. 
     AssemblyName aName = new AssemblyName("TempAssembly"); 
     AssemblyBuilder ab = currentDomain.DefineDynamicAssembly(
      aName, AssemblyBuilderAccess.Run); 

     // Define a dynamic module in "TempAssembly" assembly. For a single- 
     // module assembly, the module has the same name as the assembly. 
     ModuleBuilder mb = ab.DefineDynamicModule(aName.Name); 

     // Define a public enumeration with an underlying type of Integer. 
     EnumBuilder eb = mb.DefineEnum("MyAnimalType", TypeAttributes.Public, typeof(int)); 

     var types = new List<Type>(); 
     int Count = 0; 
     foreach (var assembly in AppDomain.CurrentDomain.GetAssemblies()) 
      try 
      { 
       types.AddRange(assembly.GetTypes().Where(x => x.IsSubclassOf(typeof(Animal)))); 
      } 
      catch { } 
     foreach (var type in types) 
      eb.DefineLiteral(type.Name, Count++); 

     // Create the type and save the assembly. 
     MyAnimals = eb.CreateType(); 
    } 

所以现在当我创建一个猫,我不能序列化它。 “InvalidOperationException:生成XML文档时发生错误。”我尝试过使用DynamicObject,并且我找到了一个动态辅助类(https://gist.github.com/martinnormark/2574972),但是当我想在封装到另一个类中时序列化一个Cat对象时,这无助于我。

public static bool Save(Animal animal) 
    { 
     System.Xml.Serialization.XmlSerializer ListSer = new System.Xml.Serialization.XmlSerializer(typeof(Animal)); 
     System.IO.StreamWriter mywriter = new System.IO.StreamWriter(@"test.txt", false); 
     ListSer.Serialize(mywriter, animal); 
     mywriter.Flush(); 
     mywriter.Close(); 
     return true; 
    } 

    public Form1() 
    { 
     InitializeComponent(); 
     GetEDIDeviceTypesEnums(); 

     Animal c = new Cat(); 
     Save(c); 

     // This way fails too 
     dynamic cat = CreateAnimal<Animal>("Cat"); 
     Save(cat); 
    } 

我为了序列化Cat而丢失了什么?

XMLSerializer需要提前知道它可以序列化的类型;如果你初始化一个抽象类的XMLSerializer,它只会知道如何序列化这个类而不是继承它。

XMLSerializer有另一个构造函数,它允许您输入一个额外类型的数组供其在尝试序列化时使用。您可以动态建立的类型从GetAssemblies数组(类似于你对建立自定义MyAnimals枚举什么):

public static bool Save(Animal animal) 
    { 
     var lListOfAnimals = (from lAssembly in AppDomain.CurrentDomain.GetAssemblies() 
         from lType in lAssembly.GetTypes() 
         where typeof(Animal).IsAssignableFrom(lType) 
         select lType).ToArray(); 

     System.Xml.Serialization.XmlSerializer ListSer = new System.Xml.Serialization.XmlSerializer(typeof(Animal), lListOfAnimals); 

代码从Yahoo Serious的回答直解禁this thread。正如Yahoo Serious提到的那样,如果经常调用Save,以这种方式使用Reflection可能会产生性能问题,因此您可能需要缓存动物类型数组,而不是每次序列化时重新构建它。

+0

我不知道谷歌搜索你做了什么来找到这个。我现在一直在寻找一整天。非常感谢!! – Tizz 2014-08-29 18:17:09