ICode9

精准搜索请尝试: 精确搜索
首页 > 编程语言> 文章详细

是否可以使一个对象的生命周期依赖于另一个对象,而无需在C#中进行强耦合?

2019-12-08 01:08:13  阅读:278  来源: 互联网

标签:events c garbage-collection


我有一些符合以下要求的工厂代码:

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具有观察者的引用.

标签:events,c,garbage-collection
来源: https://codeday.me/bug/20191208/2087835.html

本站声明: 1. iCode9 技术分享网(下文简称本站)提供的所有内容,仅供技术学习、探讨和分享;
2. 关于本站的所有留言、评论、转载及引用,纯属内容发起人的个人观点,与本站观点和立场无关;
3. 关于本站的所有言论和文字,纯属内容发起人的个人观点,与本站观点和立场无关;
4. 本站文章均是网友提供,不完全保证技术分享内容的完整性、准确性、时效性、风险性和版权归属;如您发现该文章侵犯了您的权益,可联系我们第一时间进行删除;
5. 本站为非盈利性的个人网站,所有内容不会用来进行牟利,也不会利用任何形式的广告来间接获益,纯粹是为了广大技术爱好者提供技术内容和技术思想的分享性交流网站。

专注分享技术,共同学习,共同进步。侵权联系[81616952@qq.com]

Copyright (C)ICode9.com, All Rights Reserved.

ICode9版权所有