你所在位置:首页C#.net开发 → 在C#中实现弱委托

在C#中实现弱委托

发布时间:2019-07-11

 在C#中,使用 Delegate d = Object.Method; 的方式创建一个委托,在实现上,这个委托对象内部持有了源对象的一个强引用(System.Object),如果使用者恰好有特殊需求,比如“要求源对象一旦在其他任何地方都不再使用,应该被及时回收。”,那么,一旦委托对象的生命期足够长,由于委托内部的强引用存在,源对象的销毁将被延迟,与使用者预期不符,可能会导致Bug等问题。

  比如,这里有一个简单的测试对象:

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 }  这个简单对象虽然没有成员数据,但各个方法也都生命为非Static的,因为在这里我要测试的是和对象绑定的委托,即 public static Delegate CreateDelegate(Type type, object target, string method); 方式创建的委托。另外,AddInt方法中用到了我自定义的一个函数Print,功能如其名。

  下面这段代码,演示的是强引用委托,和最直接的弱引用委托方式:

 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");  输出是:

abcabcdef  "def”只被输出了一次,是因为,第6行用new ClassForDeclTest()创建的对象并没有被专门的变量保存下来,所以第9行的GC.Collect()会将这个对象给回收掉,第10行的委托Invoke将判断WeakReferece.Target为null,于是第10行不输出任何内容。

  我这篇文章的主要目的,就是要将6、7行的弱委托创建过程提取成一个专门的工具模块。

  第一次尝试:

 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");  这种方法很简单,只要事件发送方管理一个WeakDelegate的容器,就能很方便的使用弱委托。一个明显的缺点是,使用这个WeakDelegate类,对事件发送方是侵入性的,如果发送方是类型,不能修改,比如按钮事件 public event EventHandler Click; 要求事件响应者必须是形如 public delegate void EventHandler(Object sender, EventArgs e); 的委托,所以WeakDelegate不能满足需要。

  第二次尝试:    

 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 ParameterExpression[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
上一篇:我也要学C语言
下一篇:C#泛型集合实例应用浅析