我有一些工厂代码:
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);
}
}
答案 0 :(得分:2)
当您附加到事件时,您正在创建委托并将其传递给事件源。委托持有对触发事件时要调用的对象的引用。这就是对象引用就像 “source有一个关于目标的引用” 。如果你抛弃了源,目标就不在乎了。
由于你已经介绍了工厂,所以工厂的工作应该是让通知者保持活力,即将它们保存在一个静态列表中,或者更复杂的重复使用通知程序等方案。
正如评论中所建议的那样,您可能会对观察者/可观察模式感兴趣。工厂实施IObservable<T>
,即消费者IObserver<T>
。只要您保持observable存活,任何引用的观察者都会收到通知。如果您将Rx-Extensions添加到等式中,您将获得一组丰富的方法来处理Observable。他们将例如通常允许处理观察,删除Observable有Observer的引用。
答案 1 :(得分:1)
您可以为MyNotifyingClass
创建一个基类,这是MyHandlingClass
中存储的类型:
class BaseNotifyingClass // or maybe an interface type
{
// put event in here
}
class MyNotifyingClass : public BaseNotifyingClass
{
// as before, without event
}
class MyHandlingClass
{
public MyHandlingClass (BaseNotifyingClass notifier)
{
m_notifier = notifier;
m_notifier.Notify += HandleNotification;
}
// etc...
}
class SomeFactory
{
public MyHandlingClass Create()
{
var myNotifier = new MyNotifyingClass();
var myHandler = new MyHandlingClass(myNotifier);
return myHandler;
}
// etc...
}
这样做的另一个好处是可以在类本身中封装两个类之间的链接,工厂就会成为名称所暗示的,即用于创建对象的服务。这意味着更改两个类的链接方式不需要更改工厂类。