回答

收藏

使用动态发出的POCO进行快速序列化和反序列化

技术问答 技术问答 343 人阅读 | 0 人回复 | 2023-09-14

我目前正在将SQL表行序列化为二进制格式,以进行有效存储。我将二进制数据序列化/反序列化为List每行。我正在尝试将其升级为使用POCO,该POCO将动态生成(发射),每列一个字段。
7 G8 `" T/ M$ s/ J, y9 \我一直在网上搜索数小时,偶然发现了EF,T4,ExpandoObject之类的ORM/ i$ }# n& ~  t# s
/框架,但所有这些要么使用动态对象(可以动态添加/删除属性),要么在编译之前简单地生成POCO。我不能使用模板,因为在编译时表的模式是未知的,并且使用动态对象会太过费力(并且很慢),因为我知道确切的属性集和类型。我需要为每个表生成一个POCO,其中Fields对应于列,并相应地设置数据类型(INT->
5 J" I- k) |  I' a, Yint,TEXT->字符串)。0 s$ D) w9 G6 m9 ?* G  g
生成POCO之后,我将继续使用发出的CIL获取/设置属性,就像PetaPoco对静态编译的POCO所做的一样。我希望所有这些技巧都比使用无类型列表更快,并为我提供高强度POCO,这些POCO具有强类型并且可以通过CLR加速。我是否正确地假设了这一点?您可以在运行时开始生成POCO吗?并且使用POCO会比使用POCO更快或更有效List吗?基本上,值得为此烦恼吗?我已经知道如何使用发出的CIL加速获取/设置字段。: k  Q# t& [5 U( F. h
               
5 M; `% Y8 a! A. T) t解决方案:
0 Q) ^0 R7 ^% |# L, K/ ^; y; U                1 Z9 ?- ]# Y9 m+ @

& _1 ]0 b: k( Z; o3 f" W. C: v- Y# E* l( n3 f4 H
                从评论和聊天看来,其中的关键部分仍然是创建动态类型。好的,这是一个完整的示例,显示了一个完全可序列化的(通过任何常见的序列化程序)类型。您当然可以在类型中添加更多内容-; x! a3 w4 N6 e! m$ @* h
可能是索引器,以按数字或按名称INotifyPropertyChanged等获取属性。
7 |/ w+ G2 b/ u' }/ r* f5 Q! F( l另外-关键点:您 必须 缓存并重新使用生成的Type实例。不要 守再生这个东西......你会出血内存。6 T, E( u' [! @$ ]" h
using Newtonsoft.Json;
* T4 F1 f  k% u& J' @2 |using ProtoBuf;1 C1 g- i% V; V/ Y
using System;$ Q+ _6 u; |% q8 |
using System.IO;
) G+ s+ \& N3 q* F4 m* \; uusing System.Reflection;6 k% y% ?. j) e5 T; y
using System.Reflection.Emit;; o! X, O8 G. f7 o; N9 t
using System.Runtime.Serialization;, N" Q5 b4 }1 [6 f6 [/ C
using System.Runtime.Serialization.Formatters.Binary;
1 D+ Y9 m( R% _9 ^3 R+ Uusing System.Text;  t1 s& Y" |& h: j6 W4 r8 m  Y, w& H
using System.Xml.Serialization;
+ h- Z' k' j( B& m2 B0 ipublic interface IBasicRecord
/ X8 A9 S/ y+ d/ i' [5 Z' Q{
' m% X6 v% T# K* E8 E    object this[int field] { get; set; }
1 F7 R- H( b3 G+ I}% r# A$ |9 f4 N% ^$ B. @4 g
class Program( B( D9 I$ i% d1 P# h  `' ?
{
0 @1 Z* m% G- x, W+ N$ v    static void Main()
9 _8 \3 g' K1 f9 S    {2 r. D. u$ I3 t& W* ~# j
        object o = 1;
" |& ]! `; H2 G1 i4 t        int foo = (int)o;
) o; x  k8 L% Q  _3 V: B        string[] names = { "Id", "Name", "Size", "When" };2 S, K6 ]% z. n/ _# U# U$ j8 v& }
        Type[] types = { typeof(int), typeof(string), typeof(float), typeof(DateTime?) };
! n5 a- I0 v+ ?7 ]" z& r        var asm = AppDomain.CurrentDomain.DefineDynamicAssembly(
1 p( [5 g1 d* W  X1 C            new AssemblyName("DynamicStuff"),
# s2 t# a. _7 v* c% J9 v            AssemblyBuilderAccess.Run);
# }# [0 T$ M; l$ A; {( C% J        var module = asm.DefineDynamicModule("DynamicStuff");
( Y+ f4 V6 L$ y6 i- f        var tb = module.DefineType("MyType", TypeAttributes.Public | TypeAttributes.Serializable);2 c, \/ m" v0 S) V9 m
        tb.SetCustomAttribute(new CustomAttributeBuilder(9 J( i8 H2 e9 F
            typeof(DataContractAttribute).GetConstructor(Type.EmptyTypes), new object[0]));
9 A/ N# u7 D# ?# q        tb.AddInterfaceImplementation(typeof(IBasicRecord));1 m2 D4 ^- L) C* S
        FieldBuilder[] fields = new FieldBuilder[names.Length];( G% u8 V9 P' z/ M
        var dataMemberCtor = typeof(DataMemberAttribute).GetConstructor(Type.EmptyTypes);
3 B% z2 m; F) g+ w( j2 M        var dataMemberProps = new[] { typeof(DataMemberAttribute).GetProperty("Order") };
& W; k' w& o4 l' ]* E        for (int i = 0; i  a.ParameterType);! R( c/ u# t. n  o; n  H% t) c; P. ~
                var method = tb.DefineMethod(accessor.Name,
; D( W( ]# M- {  N* F                    accessor.Attributes & ~MethodAttributes.Abstract,9 Y+ F( v, }/ q
                    accessor.CallingConvention, accessor.ReturnType, argTypes);
  ~. T4 f7 D- o6 I                tb.DefineMethodOverride(method, accessor);: u, c) `2 b( S' D8 Z! g0 c
                var il = method.GetILGenerator();
$ ]* f: m( a+ K' t7 p  ?' L7 U, Z                if (args.Length == 1 && argTypes[0] == typeof(int))+ p7 i. B# t6 ~% `2 y
                {2 l2 P! a8 R' `" V5 D7 d8 w
                    var branches = new Label[fields.Length];7 x- c# q+ P$ F$ l
                    for (int i = 0; i  a.ParameterType);
. i$ d' O$ j+ Q                var method = tb.DefineMethod(accessor.Name,
/ o# B9 l2 s% ]6 K" T& u3 _  W                    accessor.Attributes & ~MethodAttributes.Abstract,
$ |# C; j0 W5 e) R& H# z                    accessor.CallingConvention, accessor.ReturnType, argTypes);
2 Q3 |( |1 g6 `7 e+ I                tb.DefineMethodOverride(method, accessor);- h* {1 w1 @% }9 f7 w0 S: k2 @9 N
                var il = method.GetILGenerator();1 L: v- A6 b4 m
                if (args.Length == 2 && argTypes[0] == typeof(int) && argTypes[1] == typeof(object))
+ N& _8 o; B& F  x' Z                {- r7 ?. _4 _! R  C
                    var branches = new Label[fields.Length];! Y+ ]& K. |3 I/ f
                    for (int i = 0; i 输出:
, ?3 }, L4 U9 C* I' rXmlSerializer: 246 bytes6 i: @% j& T) |3 ]  R
Json.NET: 81 bytes
) j. {3 P6 ]" t4 |. D) C9 _DataContractSerializer: 207 bytes( Q! H% a+ s+ H, G
protobuf-net: 25 bytes
4 s0 [+ J6 c' ^) W4 Y; e" p, @+ {BinaryFormatter: 182 bytes
分享到:
您需要登录后才可以回帖 登录 | 立即注册

本版积分规则