我有一些符合以下要求的工厂代码:
public MyHandlingClass Create()
{
var myHandler = new MyHandlingClass();
var myNotifier = new MyNotifyingClass();
myNotifier.Notify += myHandler.HandleNotification;
return myHandler;
}
这个想法是允许MyHandlingClass对外部信号做出反应而不必关心发送者的类型.然后,在不同的应用程序中,包含上述方法的工厂类可以将MyNotifyingClass替换为其他能够引发类似事件类型的类.
在实际的代码中,MyNotifyingClass处理来自非托管DLL的事件:
public class MyNotifyingClass
{
private EventHandler notify;
private UnmanagedEventHandler unmanagedNotify;
public event EventHandler Notify
{
add
{
this.notify += value;
// Hold on to a strong reference to the delegate passed into the
// unmanaged DLL, to avoid garbage collection of the delegate:
this.unmanagedNotify = HandleUnmanagedNotify;
NativeMethods.SetNotifyCallback(this.unmanagedNotify);
}
remove
{
this.notify -= value;
}
}
private void HandleUnmanagedNotify(IntPtr sender, IntPtr eventArgs)
{
this.notify(this, eventArgs.Empty);
}
}
但是,当我从工厂方法返回时,不再有任何对myNotifier实例的强引用,并且最终将对其进行垃圾回收,当我的非托管DLL尝试调用回调时,将导致访问冲突.
我想以某种方式强制myNotifier实例具有与myHandler实例相同的生存期.但是我并不特别喜欢让MyNotifierClass保持对处理程序对象的强引用的想法.毕竟,一旦布线到位,它就不再对实际对象有用.
我能以某种方式在两个班级之间建立牢固的关系,而仍然让他们不了解彼此的存在吗?
(编辑:总而言之,这个代码片段似乎重现了我的问题:)
[TestClass]
public class MyTests
{
public class MyHandler
{
public void Handle(object sender, EventArgs e)
{ }
}
public class MyNotifier
{
public event EventHandler Notify;
}
[TestMethod]
public void TestsSomeCondition()
{
var myHandler = new MyHandler();
var myNotifier = new MyNotifier();
myNotifier.Notify += myHandler.Handle;
var weakNotifierRef = new WeakReference(myNotifier);
myNotifier = null;
GC.Collect();
Assert.IsTrue(weakNotifierRef.IsAlive);
}
}
解决方法:
当您附加到事件时,您将创建一个委托并将其传递给事件源.引发事件时,委托持有对要调用的对象的引用.那就是对象引用就像“源在目标上有引用”一样.如果您将源扔掉,目标将不在乎.
由于您已经介绍了工厂,因此使通知程序保持活动状态应该是工厂的工作,即通过将通知程序保持在静态列表中或更详细地重用通知程序等方案来进行工作.
如评论中所建议,您可能会对观察者/可观察模式感兴趣.工厂实施IObservable T. ,消费者IObserver< T> .只要您保持可观察到的生命,就会通知所有引用的观察者.如果将Rx-Extensions添加到方程式中,则会得到一组丰富的方法来处理Observables.他们将例如通常允许处置观察,删除对Observable具有观察者的引用.