我能让一个对象的生存期依赖于另一个对象而不需要c#中的强耦合吗?

本文关键字:一个对象 耦合 不需要 生存期 依赖于 | 更新日期: 2023-09-27 18:08:12

我有一些工厂代码如下:

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

我能让一个对象的生存期依赖于另一个对象而不需要c#中的强耦合吗?

当您附加到一个事件时,您正在创建一个委托并将其传递给事件源。委托持有对事件触发时要调用的对象的引用。即对象引用类似于"源对目标有引用"。如果你把源扔掉,目标不会在意。

既然你已经引入了工厂,那么工厂的工作应该是保持通知器的活动,即通过将它们保存在静态列表或更详细的重用通知器的方案中等等。

正如评论中建议的那样,你可能会对观察者/可观察模式感兴趣。工厂实现IObservable<T>,消费者实现IObserver<T>。只要你保持可观察对象存活,任何被引用的观察者都会被通知。如果你将Rx-Extensions添加到这个等式中,你就会得到一组丰富的方法来处理observable。例如,它们通常允许处理一个观察对象,删除Observable拥有观察者的引用。

您可以为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...
}

这样做的额外好处是将两个类之间的链接封装在类本身中,并且工厂变成了顾名思义的用于创建对象的服务。这意味着更改两个类的链接方式不需要更改工厂类。