序列化/反序列化动态对象 [英] Serialize/Deserialize a dynamic object

查看:224
本文介绍了序列化/反序列化动态对象的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我有以下类:

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

它从动态创建的枚举MyAnimals获取其myType:

It gets its 'myType' from the dynamically created enum '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对象封装在另一个类中时,它不会有帮助。

So now when I create a cat, I cannot serialize it. "InvalidOperationException: There was an error generating the XML document." I have tried using DynamicObject, and I found a dynamic helper class (https://gist.github.com/martinnormark/2574972) but that doesnt help when I want to serialize a Cat object when its encapsulated in another class.

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

为了序列化一个猫,我缺少什么?

What am I missing in order to serialize a Cat?

推荐答案

XMLSerializer需要提前知道可以序列化的类型;如果您在抽象类中初始化一个XMLSerializer,它将只知道如何序列化该类,而不是任何继承它。

The XMLSerializer needs to know ahead of time what types it can serialize; if you initialize an XMLSerializer on an abstract class, it will only know how to serialize that class and not anything inheriting it.

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

XMLSerializer has another constructor that allows you to input an array of extra types for it to use when trying to serialize. You can dynamically build that array of types from GetAssemblies (similar to what you did to build your custom MyAnimals Enum):

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

直接从雅虎认证'回答在此线程 。正如雅虎严重提到的,如果您经常打电话给保存,则以这种方式使用反射可能会导致性能下降,因此您可以缓存Animal类型的数组,而不是每次序列化时重建它。

Code lifted straight from Yahoo Serious' answer in this thread. As Yahoo Serious mentions, if you call Save often, using Reflection in this way may create a performance hit, so you might cache the array of Animal types rather than rebuilding it every time you serialize.

这篇关于序列化/反序列化动态对象的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆