c# – 使用动态发射的POCO进行快速序列化和反序列化

c# – 使用动态发射的POCO进行快速序列化和反序列化,第1张

概述我目前正在将SQL表行序列化为二进制格式以实现高效存储.我将二进制数据序列化/反序列化为List< object>每排.我正在尝试将其升级为使用POCO,这将通过每列一个字段动态生成(发出). 我一直在网上搜索几个小时,偶然发现了像EF,T4,ExpandoObject这样的ORM /框架,但所有这些都使用动态对象(可以动态添加/删除属性)或者在编译之前简单地生成POCO.我不能使用模板,因为表的 我目前正在将sql表行序列化为二进制格式以实现高效存储.我将二进制数据序列化/反序列化为List< object>每排.我正在尝试将其升级为使用POCO,这将通过每列一个字段动态生成(发出).

我一直在网上搜索几个小时,偶然发现了像EF,T4,ExpandoObject这样的ORM /框架,但所有这些都使用动态对象(可以动态添加/删除属性)或者在编译之前简单地生成POCO.我不能使用模板,因为表的模式在编译时是未知的,并且使用动态对象会过度(而且速度慢),因为我知道确切的属性集及其类型.我需要为每个表生成一个POCO,其中FIElds对应于列,并且相应地设置数据类型(INT – > int,TEXT – > string).

在生成POCO之后,我将继续使用发出的CIL来获取/设置属性,就像PetaPoco does for statically compiled POCOs一样.我希望所有这些钻井平台都比使用无类型列表更快,并且给我高强度的POCO – 键入并可以由CLR加速.我认为这是正确的吗?你可以在运行时创建POCO吗?与使用List< object>相比,使用POCO会更快或更节省内存吗?基本上,值得麻烦吗?我已经知道如何使用发出的CIL加速获取/设置字段.

解决方法 从评论和聊天中,似乎关键部分仍然是创建动态类型;好的,这是一个完整的示例,显示完全可序列化(通过任何常见的序列化程序)类型.您当然可以添加更多类型 – 可能是索引器按数字或名称获取属性,INotifyPropertyChanged等.

此外 – 关键点:您必须缓存并重新使用生成的Type实例.不要让这些东西再生……你会出血记忆.

using Newtonsoft.Json;using ProtoBuf;using System;using System.IO;using System.Reflection;using System.Reflection.Emit;using System.Runtime.Serialization;using System.Runtime.Serialization.Formatters.Binary;using System.Text;using System.Xml.Serialization;public interface IBasicRecord{    object this[int fIEld] { get; set; }}class Program{    static voID Main()    {        object o = 1;        int foo = (int)o;        string[] names = { "ID","name","Size","When" };        Type[] types = { typeof(int),typeof(string),typeof(float),typeof(DateTime?) };        var asm = AppDomain.CurrentDomain.defineDynamicAssembly(            new Assemblyname("DynamicStuff"),AssemblyBuilderAccess.Run);        var module = asm.defineDynamicModule("DynamicStuff");        var tb = module.defineType("MyType",TypeAttributes.Public | TypeAttributes.Serializable);        tb.SetCustomAttribute(new CustomAttributeBuilder(            typeof(DataContractAttribute).GetConstructor(Type.EmptyTypes),new object[0]));        tb.AddInterfaceImplementation(typeof(IBasicRecord));        FIEldBuilder[] fIElds = new FIEldBuilder[names.Length];        var dataMemberCtor = typeof(DataMemberAttribute).GetConstructor(Type.EmptyTypes);        var dataMemberProps = new[] { typeof(DataMemberAttribute).GetProperty("Order") };        for (int i = 0; i < fIElds.Length; i++)        {            var fIEld = fIElds[i] = tb.defineFIEld("_" + names[i],types[i],FIEldAttributes.Private);            var prop = tb.defineProperty(names[i],PropertyAttributes.None,Type.EmptyTypes);            var getter = tb.defineMethod("get_" + names[i],MethodAttributes.Public | MethodAttributes.HIDeBySig,Type.EmptyTypes);            prop.Setgetmethod(getter);            var il = getter.GetILGenerator();            il.Emit(OpCodes.Ldarg_0); // this            il.Emit(OpCodes.Ldfld,fIEld); // .Foo            il.Emit(OpCodes.Ret); // return            var setter = tb.defineMethod("set_" + names[i],typeof(voID),new Type[] { types[i] });            prop.SetSetMethod(setter);            il = setter.GetILGenerator();            il.Emit(OpCodes.Ldarg_0); // this            il.Emit(OpCodes.Ldarg_1); // value            il.Emit(OpCodes.Stfld,fIEld); // .Foo =            il.Emit(OpCodes.Ret);            prop.SetCustomAttribute(new CustomAttributeBuilder(                dataMemberCtor,new object[0],dataMemberProps,new object[1] { i + 1 }));        }        foreach (var prop in typeof(IBasicRecord).GetPropertIEs())        {            var accessor = prop.Getgetmethod();            if (accessor != null)            {                var args = accessor.GetParameters();                var argTypes = Array.ConvertAll(args,a => a.ParameterType);                var method = tb.defineMethod(accessor.name,accessor.Attributes & ~MethodAttributes.Abstract,accessor.CallingConvention,accessor.ReturnType,argTypes);                tb.defineMethodoverrIDe(method,accessor);                var il = method.GetILGenerator();                if (args.Length == 1 && argTypes[0] == typeof(int))                {                    var branches = new Label[fIElds.Length];                    for (int i = 0; i < fIElds.Length; i++)                    {                        branches[i] = il.defineLabel();                    }                    il.Emit(OpCodes.Ldarg_1); // key                    il.Emit(OpCodes.Switch,branches); // switch                    // default:                    il.ThrowException(typeof(ArgumentOutOfRangeException));                    for (int i = 0; i < fIElds.Length; i++)                    {                        il.MarkLabel(branches[i]);                        il.Emit(OpCodes.Ldarg_0); // this                        il.Emit(OpCodes.Ldfld,fIElds[i]); // .Foo                        if (types[i].IsValueType)                        {                            il.Emit(OpCodes.Box,types[i]); // (object)                        }                        il.Emit(OpCodes.Ret); // return                    }                }                else                {                    il.ThrowException(typeof(NotImplementedException));                }            }            accessor = prop.GetSetMethod();            if (accessor != null)            {                var args = accessor.GetParameters();                var argTypes = Array.ConvertAll(args,accessor);                var il = method.GetILGenerator();                if (args.Length == 2 && argTypes[0] == typeof(int) && argTypes[1] == typeof(object))                {                    var branches = new Label[fIElds.Length];                    for (int i = 0; i < fIElds.Length; i++)                    {                        branches[i] = il.defineLabel();                    }                    il.Emit(OpCodes.Ldarg_1); // key                    il.Emit(OpCodes.Switch,branches); // switch                    // default:                    il.ThrowException(typeof(ArgumentOutOfRangeException));                    for (int i = 0; i < fIElds.Length; i++)                    {                        il.MarkLabel(branches[i]);                        il.Emit(OpCodes.Ldarg_0); // this                        il.Emit(OpCodes.Ldarg_2); // value                        il.Emit(types[i].IsValueType ? OpCodes.UnBox_Any : OpCodes.Castclass,types[i]); // (SomeType)                        il.Emit(OpCodes.Stfld,fIElds[i]); // .Foo =                        il.Emit(OpCodes.Ret); // return                    }                }                else                {                    il.ThrowException(typeof(NotImplementedException));                }            }        }        var type = tb.CreateType();        var obj = Activator.CreateInstance(type);        // we'll use the index (via a kNown interface) to set the values        IBasicRecord rec = (IBasicRecord)obj;        rec[0] = 123;        rec[1] = "abc";        rec[2] = 12F;        rec[3] = DateTime.Now;        for (int i = 0; i < 4; i++)        {            Console.Writeline("{0} = {1}",i,rec[i]);        }        using (var ms = new MemoryStream())        {            var ser = new XmlSerializer(type);            ser.Serialize(ms,obj);            Console.Writeline("XmlSerializer: {0} bytes",ms.Length);        }        using (var ms = new MemoryStream())        {            using (var writer = new StreamWriter(ms,EnCoding.UTF8,1024,true))            {                var ser = new JsonSerializer();                ser.Serialize(writer,obj);            }            Console.Writeline("Json.NET: {0} bytes",ms.Length);        }        using (var ms = new MemoryStream())        {            var ser = new DataContractSerializer(type);            ser.WriteObject(ms,obj);            Console.Writeline("DataContractSerializer: {0} bytes",ms.Length);        }        using (var ms = new MemoryStream())        {            Serializer.NonGeneric.Serialize(ms,obj);            Console.Writeline("protobuf-net: {0} bytes",ms.Length);        }        using (var ms = new MemoryStream())        {            // note: NEVER do this unless you have a custom Binder; your            // assembly WILL NOT deserialize in the next AppDomain (i.e.            // the next time you load your app,you won't be able to load)            // - shown only for illustration            var bf = new BinaryFormatter();            bf.Serialize(ms,obj);            Console.Writeline("BinaryFormatter: {0} bytes",ms.Length);        }    }}

输出:

XmlSerializer: 246 bytesJson.NET: 81 bytesDataContractSerializer: 207 bytesprotobuf-net: 25 bytesBinaryFormatter: 182 bytes
总结

以上是内存溢出为你收集整理的c# – 使用动态发射的POCO进行快速序列化和反序列化全部内容,希望文章能够帮你解决c# – 使用动态发射的POCO进行快速序列化和反序列化所遇到的程序开发问题。

如果觉得内存溢出网站内容还不错,欢迎将内存溢出网站推荐给程序员好友。

欢迎分享,转载请注明来源:内存溢出

原文地址: http://outofmemory.cn/langs/1223753.html

(0)
打赏 微信扫一扫 微信扫一扫 支付宝扫一扫 支付宝扫一扫
上一篇 2022-06-05
下一篇 2022-06-05

发表评论

登录后才能评论

评论列表(0条)

保存