Implement weak delegation in C #

Source: Internet
Author: User

In C #, use Delegate d = Object. create a delegate. In terms of implementation, this delegate object holds a strong reference (System. object). If the user has special requirements, for example, "the source Object should be recycled in a timely manner once it is no longer used anywhere else. ", Once the life cycle of the delegate object is long enough, the destruction of the source object will be delayed due to the strong internal references of the Delegate, which may lead to bugs and other problems.

For example, there is a simple test object:

1 class ClassForDeclTest2 {3 public string GetString () {return "call GetString";} 4 public int AddInt (int a, int B) {return a + B ;} 5 public void PrintString (string s) {Print (s) ;}6} Although this simple object does not have member data, every method is not Static, here I want to test the Delegate bound to the object, that is, the Delegate created by using the public static Delegate CreateDelegate (Type type, object target, string method); method. In addition, the AddInt method uses a custom function Print, as its name.

The following code demonstrates the strong reference delegation and the most direct weak reference delegation method:

1 Action <string> a = new ClassForDeclTest (). printString; 2 a ("abc"); 3 GC. collect (); 4 a ("abc"); 5 6 WeakReference weakRef = new WeakReference (new ClassForDeclTest (); 7 a = (s) => {object o = weakRef. target; if (o! = Null) Print (s) ;}; 8 a ("def"); 9 GC. Collect (); 10 a ("def"); the output is:

Abcabcdef "def" is output only once because the object created in row 6th with new ClassForDeclTest () is not saved by special variables, so GC in row 9th is performed. collect () recycles the object, and the 10th-row delegate Invoke will judge WeakReferece. the Target is null, so no content is output in row 10th.

The main purpose of this article is to extract the weak delegate creation process of lines 6 and 7 into a dedicated tool module.

First Attempt:

1 class WeakDelegate 2 {3 public WeakDelegate (object o, string methodName): 4 this (o, o. getType (). getMethod (methodName) 5 {6} 7 8 public WeakDelegate (object o, MethodInfo method) 9 {10 m_target = new WeakReference (o); 11 m_method = method; 12} 13 14 public object Invoke (params object [] args) 15 {16 object target = m_target.Target; 17 if (target! = Null) return m_method.Invoke (target, args); 18 else return null; 19} 20 21 private WeakReference m_target; 22 private MethodInfo m_method; 23} 24 25 WeakDelegate d = new WeakDelegate (new ClassForDeclTest (), "PrintString"); 26 d. invoke ("abc"); 27 GC. collect (); 28 d. invoke ("abc"); this method is very simple. As long as the event sender manages a WeakDelegate container, it is very convenient to use the weak delegate. One obvious drawback is that using this WeakDelegate class is invasive to event senders. If the sender is of the system type, it cannot be modified. For example, the button event public event implements EventHandler Click; the event responder must be a delegate in the form of public delegate void EventHandler (Object sender, EventArgs e); so WeakDelegate cannot meet the requirements.

Second Attempt:

1 class WeakDelegate 2 {3 public WeakDelegate (object o, string methodName): 4 this (o, o. getType (). getMethod (methodName) 5 {6} 7 8 public WeakDelegate (object o, MethodInfo method) 9 {10 m_target = new WeakReference (o); 11 m_method = method; 12} 13 14 public Delegate ToDelegate () 15 {16 ParameterExpression [] parExps = null; 17 {18 ParameterInfo [] parInfos = m_method.GetParameters (); 19 parExps = new P ArameterExpression [parInfos. length]; 20 for (int I = 0; I <parExps. length; ++ I) 21 {22 parExps [I] = Expression. parameter (parInfos [I]. parameterType, "p" + I); 23} 24} 25 26 Expression target = Expression. field (Expression. constant (this), GetType (). getField ("m_target", BindingFlags. instance | BindingFlags. nonPublic); 27 target = Expression. convert (Expression. property (target, "Target"), m_method.Reflect EdType); 28 29 Expression body = 30 Expression. condition (31 Expression. notEqual (target, Expression. constant (null), 32 Expression. call (target, m_method, parExps), 33 GetTypeDefaultExpression (m_method.ReturnType); 34 35 return Expression. lambda (body, parExps ). compile (); 36} 37 38 private static Expression GetTypeDefaultExpression (Type t) 39 {40 if (t = typeof (void) return Expression. call (typeof (WeakDe Lew.helper ). getMethod ("EmptyFunc", BindingFlags. nonPublic | BindingFlags. static); 41 else if (t. isClass) return Expression. constant (null, t); 42 else return Expression. constant (t. invokeMember (null, BindingFlags. createInstance, null); 43} 44 45 private WeakReference m_target; 46 private MethodInfo m_method; 47} This class is changed by removing the Invoke method and adding ToDelegate, the latter function is to generate A Func <> or Ction <> type delegate. The WeakReference object calls the token generated by ToDelegate and can be used for various occasions that require delegation, such as the Click Event Response of the preceding button. The usage of this class is as follows: (Func <string>) new WeakDelegate (new ClassForDeclTest (), "GetString "). toDelegate (); although no special variables are used to store the WeakDelegate object, the delegate generated by ToDelegate contains a strongly referenced WeakDelegate object (Expression. constant (this), and WeakDelegate holds weak references to the source object, so the destruction of the source object is not affected and can be achieved.

The test is as follows:

1 // output a delegate execution time 2 public static void PerfTimer (Action f, params string [] name) 3 {4 Assert (name. length <= 1); 5 6 Stopwatch watch = new Stopwatch (); 7 watch. start (); 8 f (); 9 watch. stop (); 10 float seconds = (watch. elapsedMilliseconds/1000.0f); 11 12 if (name. length> 0) Print (name [0], ":", seconds); 13 else Print (seconds ); 14} 15 16 // Performance Test help type 17 class ClassForPerfTest18 {19 public int N {get; set;} 20 public void Inc () {N + = 1 ;} 21} 22 23... 24 25 {26 Print ("------- test: Func <string> -------"); 27 28 & nb

Related Article

Contact Us

The content source of this page is from Internet, which doesn't represent Alibaba Cloud's opinion; products and services mentioned on that page don't have any relationship with Alibaba Cloud. If the content of the page makes you feel confusing, please write us an email, we will handle the problem within 5 days after receiving your email.

If you find any instances of plagiarism from the community, please send an email to: info-contact@alibabacloud.com and provide relevant evidence. A staff member will contact you within 5 working days.

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.