我一直在网上搜索几个小时,偶然发现了像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进行快速序列化和反序列化所遇到的程序开发问题。
如果觉得内存溢出网站内容还不错,欢迎将内存溢出网站推荐给程序员好友。
欢迎分享,转载请注明来源:内存溢出
评论列表(0条)