首页 > 代码库 > 将委托持久化及利用表达式树从持久化库还原委托

将委托持久化及利用表达式树从持久化库还原委托

在领域事件中,有时为了数据的一致性,需要先将事件持久化,然后在读取数据时还原并执行事件保证数据一致。

持久化委托时,我们需要持久化委托的类型、方法名称和方法参数类型。

如申明一个委托:

 public delegate void DomainEventHandler(object sender, BaseDomainEventArgs eventArgs);

定义一个事件:

public static event DomainEventHandler HelloDomainEvent;

获取事件订阅委托列表,并获取委托的类型、方法名称和方法参数类型

 1 foreach (var item in HelloDomainEvent.GetInvocationList())//按照调用顺序返回此多路广播委托的调用列表。
 2 {
 3     var eventType = item.Target.GetType().AssemblyQualifiedName;//获取当前委托调用者的 System.Type 的程序集限定名,其中包括从中加载 System.Type 的程序集的名称
 4     var eventMethodName = item.Method.Name;//获取委托表示方法的名称
 5     var eventMethodParamaters = item.Method.GetParameters();//获取委托表示方法的参数
 6     String[] eventMethodParamaterTypes = new String[eventMethodParamaters.Length];//委托表示方法的参数类型
 7     var index = 0;
 8     foreach (var paramater in eventMethodParamaters)
 9     {
10          eventMethodParamaterTypes[index] = paramater.ParameterType.AssemblyQualifiedName;//获取参数的System.Type 的程序集限定名,其中包括从中加载 System.Type 的程序集的名称
11         index++;
12     }
13 } 

可以将 eventType ,eventMethodName ,eventMethodParamaterTypes 持久化在数据库或本地文件中。

接下来是从持久化库中还原委托:

 1         private TDelegator CreateDelegator<TDelegator>(String strEventType,String eventMethodName,String[] strEventMethodParameterTypes)
 2         {
 3             var eventType = Type.GetType(strEventType);                         //获得委托调用者类型
 4             var target = eventType.Assembly.CreateInstance(eventType.FullName); //实例化委托调用者
 5             var targetConstant = Expression.Constant(target, eventType);        //创建委托调用常量表达式
 6 
 7             ParameterExpression[] arguments = new ParameterExpression[strEventMethodParameterTypes.Length];//创建参数表达式数组
 8 
 9             var index = 0;
10             foreach (var item in strEventMethodParameterTypes)
11             {
12                 arguments[index] = Expression.Parameter(Type.GetType(strEventMethodParameterTypes[index]));//创建参数表达式,并将其赋值给数表达式数组
13                 index++;
14             }
15 
16             var methodCallExp = Expression.Call(targetConstant, eventType.GetMethod(eventMethodName), arguments);//创建一个表示调用带参数的方法的MethodCallExpression。
17             //Expression.Lambda<TDelegator>(methodCallExp, arguments) 返回以表达式目录树的形式将强类型 lambda 表达式表示为数据结构的 Expression<TDelegate>
18             //Expression<TDelegate>.Compile()  将表达式树描述的 lambda 表达式编译为可执行代码,并生成表示该 lambda 表达式的委托
19             return Expression.Lambda<TDelegator>(methodCallExp, arguments).Compile();
20         }

为了保证数据一致,我们在执行还原的委托时还需要知道当时委托传入的参数,所以在持久化委托时,我们还要获取到委托传入的参数,并持久化。

简单示例:

 1     /// <summary>
 2      /// 领域事件委托
 3      /// </summary>
 4      /// <param name="sender"></param>
 5      /// <param name="eventArgs"></param>
 6      /// <summary>
 7     public delegate void DomainEventHandler(object sender, BaseDomainEventArgs eventArgs);
 8     public class DomainEventTest2 : BaseTest
 9     {
10         /// 事件
11         /// </summary>
12         public static event DomainEventHandler HelloDomainEvent;
13 
14         private List<Dictionary<String, Object>> eventStort = new List<Dictionary<string, Object>>();//事件及调用参数持久化
15 
16         public override void Test()
17         {
18             var chinaSayHelloHandler = new ChinaSayHelloHandler();
19             var englishSayHelloHandler = new EnglishSayHelloHandler();
20             {
21                 HelloDomainEvent += chinaSayHelloHandler.Handler;
22                 HelloDomainEvent += englishSayHelloHandler.Handler;
23                 WriteLine("持久化事件中。。。");
24                 Persistence(HelloDomainEvent, new SayEventArgs() { Message = "在见面时打招呼" });
25                 WriteLine("持久化事件完成");
26             }
27             {
28                 WriteLine("加载并执行事件中。。。");
29                 foreach (var item in eventStort)
30                 {
31                     object objEventType = null;
32                     object objEventMethodName = null;
33                     object objEventMethodParamaterTypes = null;
34                     object objEventArgs = null;
35                     item.TryGetValue("eventType", out objEventType);
36                     item.TryGetValue("eventMethodName", out objEventMethodName);
37 
38                     item.TryGetValue("eventMethodParamaterTypes", out objEventMethodParamaterTypes);//如为JSon格式还需反序列化成原来对象
39                     item.TryGetValue("eventArgs", out objEventArgs);//如为JSon格式还需反序列化成原来对象
40 
41                     var delegator = CreateDelegator<DomainEventHandler>(objEventType.ToString(),objEventMethodName.ToString(),objEventMethodParamaterTypes as String[]);
42                     var eventType = Type.GetType(objEventType.ToString());              //获得委托调用者类型
43                     var target = eventType.Assembly.CreateInstance(eventType.FullName); //实例化委托调用者
44                     delegator(eventType, objEventArgs as BaseDomainEventArgs);
45                 }
46                 WriteLine("加载并执行事件完成");
47             }
48         }
49 
50         private void Persistence(DomainEventHandler DomainEvent, BaseDomainEventArgs eventArgs)
51         {
52             foreach (var item in HelloDomainEvent.GetInvocationList())//按照调用顺序返回此多路广播委托的调用列表。
53             {
54                 var dic = new Dictionary<String, Object>();
55                 var eventType = item.Target.GetType().AssemblyQualifiedName;//获取当前委托调用者的 System.Type 的程序集限定名,其中包括从中加载 System.Type 的程序集的名称
56                 var eventMethodName = item.Method.Name;//获取委托表示方法的名称
57                 var eventMethodParamaters = item.Method.GetParameters();//获取委托表示方法的参数
58                 String[] eventMethodParamaterTypes = new String[eventMethodParamaters.Length];//委托表示方法的参数类型
59                 var index = 0;
60                 foreach (var paramater in eventMethodParamaters)
61                 {
62                     eventMethodParamaterTypes[index] = paramater.ParameterType.AssemblyQualifiedName;//获取参数的System.Type 的程序集限定名,其中包括从中加载 System.Type 的程序集的名称
63                     index++;
64                 }
65                 dic.Add("eventType", eventType);
66                 dic.Add("eventMethodName", eventMethodName);
67                 dic.Add("eventMethodParamaterTypes", eventMethodParamaterTypes);//可转为JSon格式保存
68                 dic.Add("eventArgs", eventArgs);//可转为JSon格式保存
69                 eventStort.Add(dic);
70             }
71         }
72 
73         private TDelegator CreateDelegator<TDelegator>(String strEventType, String eventMethodName, String[] strEventMethodParameterTypes)
74         {
75             var eventType = Type.GetType(strEventType);                         //获得委托调用者类型
76             var target = eventType.Assembly.CreateInstance(eventType.FullName); //实例化委托调用者
77             var targetConstant = Expression.Constant(target, eventType);        //创建委托调用常量表达式
78 
79             ParameterExpression[] arguments = new ParameterExpression[strEventMethodParameterTypes.Length];//创建参数表达式数组
80 
81             var index = 0;
82             foreach (var item in strEventMethodParameterTypes)
83             {
84                 arguments[index] = Expression.Parameter(Type.GetType(strEventMethodParameterTypes[index]));//创建参数表达式,并将其赋值给数表达式数组
85                 index++;
86             }
87 
88             var methodCallExp = Expression.Call(targetConstant, eventType.GetMethod(eventMethodName), arguments);//创建一个表示调用带参数的方法的MethodCallExpression。
89             //Expression.Lambda<TDelegator>(methodCallExp, arguments) 返回以表达式目录树的形式将强类型 lambda 表达式表示为数据结构的 Expression<TDelegate>
90             //Expression<TDelegate>.Compile()  将表达式树描述的 lambda 表达式编译为可执行代码,并生成表示该 lambda 表达式的委托
91             return Expression.Lambda<TDelegator>(methodCallExp, arguments).Compile();
92         }
93     }
    /// <summary>
    /// 领域事件参数
    /// </summary>
    public abstract class BaseDomainEventArgs: EventArgs
    {
    }
1     /// <summary>
2     /// 领域事件处理
3     /// </summary>
4     public abstract class BaseDomainEventHandler
5     {
6         public abstract void Handler(object sender, BaseDomainEventArgs eventArgs);
7     }
    public class SayEventArgs: BaseDomainEventArgs
    {
        private String message;
        public String Message { get { return message; } set { message = value.ToUpper(); } }
    }
    public class ChinaSayHelloHandler : BaseDomainEventHandler
    {
        public override void Handler(object sender, BaseDomainEventArgs eventArgs)
        {
            SayEventArgs sayEventArgs = (SayEventArgs)eventArgs;
            Console.WriteLine("{0}:中国说你好", sayEventArgs.Message);   
        }
    }

    public class EnglishSayHelloHandler : BaseDomainEventHandler
    {
        public override void Handler(object sender, BaseDomainEventArgs eventArgs)
        {
            SayEventArgs sayEventArgs = (SayEventArgs)eventArgs;
            Console.WriteLine("{0}:English Say Hello", sayEventArgs.Message);
        }
    }

    public class ChinaSayByeByeHandler : BaseDomainEventHandler
    {
        public override void Handler(object sender, BaseDomainEventArgs eventArgs)
        {
            SayEventArgs sayEventArgs = (SayEventArgs)eventArgs;
            Console.WriteLine("{0}:中国说再见", sayEventArgs.Message);
        }
    }

    public class EnglishSyeByeBayHandler : BaseDomainEventHandler
    {
        public override void Handler(object sender, BaseDomainEventArgs eventArgs)
        {
            SayEventArgs sayEventArgs = (SayEventArgs)eventArgs;
            Console.WriteLine("{0}:English Say Bye Bye", sayEventArgs.Message);
        }
    }

执行结果:

技术分享

 

将委托持久化及利用表达式树从持久化库还原委托