1. 程式人生 > >將委托持久化及利用表達式樹從持久化庫還原委托

將委托持久化及利用表達式樹從持久化庫還原委托

限定 pre ole 表示 eth persist static tor .get

在領域事件中,有時為了數據的一致性,需要先將事件持久化,然後在讀取數據時還原並執行事件保證數據一致。

持久化委托時,我們需要持久化委托的類型、方法名稱和方法參數類型。

如申明一個委托:

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

執行結果:

技術分享

將委托持久化及利用表達式樹從持久化庫還原委托