【问题标题】:destroying object doesn't remove delegate from invocation list销毁对象不会从调用列表中删除委托
【发布时间】:2017-06-08 07:41:19
【问题描述】:

我的对象有点问题... 我有一个对象,里面有一个委托,它在构造函数中订阅。 当我销毁这个对象时,调用列表仍然告诉我它有一个订阅者。当我再次创建这个对象时,我找到了两个订阅者(我已经销毁的旧订阅者和新订阅者)。 我该如何解决这个问题并干净地删除列表中的订阅者?

这里是测试代码:(里面有两个按钮来销毁和创建对象)

public partial class Form1 : Form
{
    testdelegate thisdelegatetest;
    public Form1()
    {
        InitializeComponent();
        thisdelegatetest = new testdelegate();//create object 
        Timer mytimer = new Timer();//timer to see something BEGIN
        mytimer.Interval = 1000;
        mytimer.Tick += new EventHandler(mytimer_Tick);
        mytimer.Start();//timer to see something END
    }
    protected void mytimer_Tick(object sender, EventArgs e)
    {//each 1second look at the list invocation
        lb_IndelList.Text = "actual subscribers : " + testdelegate.dl_myfunctionthatcopy.GetInvocationList().Count().ToString();
    }
    private void DestroyObject_Click(object sender, EventArgs e)
    {//destroy object
    /*edit*/
        thisdelegatetest.Delete();
        thisdelegatetest = null;//dereferencing for GC
    /*edit*/
    }

    private void CreateObject_Click(object sender, EventArgs e)
    {//create object
        thisdelegatetest = new testdelegate();
    }

}
public class testdelegate
{
    public delegate void del_copysomething(int newvaluetocopy);
    internal static del_copysomething dl_myfunctionthatcopy;
    public int valueforallobject = 0;

    public testdelegate()//ctor
    {
        dl_myfunctionthatcopy += new del_copysomething(copythisint);
    }
    /*edit*/
    public void Delete()
    { 
        dl_myfunctionthatcopy -= new del_copysomething(copythisint);
    }
    /*edit*/
    private void copythisint(int newvalue)
    {
        valueforallobject = newvalue;
    }
}

感谢您的帮助。

【问题讨论】:

  • 将变量设置为null 不会“销毁”一个对象。无论您对 C# 中对象如何工作的心智模型是什么,都是错误的。
  • 您能解释一下您所做的修改吗?
  • 请不要编辑您的问题,使其不再显示问题,因此没有意义
  • 编辑的内容在 /*edit*/ 引号之间。我认为很清楚。

标签: c# object delegates destroy


【解决方案1】:
private void DestroyObject_Click(object sender, EventArgs e)
{//destroy object
    thisdelegatetest = null;
}

这并没有真正破坏对象。垃圾收集器“销毁”(释放)对象。

事实上,它不能被标记为可收集,因为static 委托仍然引用它。因此,析构函数永远不会被调用。您已手动删除订阅者,例如通过公共方法。

【讨论】:

  • 除非在这种情况下,该对象将不符合 GC 条件,正是因为有一个委托仍在引用它
  • "在调用析构函数之前需要两个垃圾回收周期。" - 你能提供一个参考来支持这个说法吗?
  • “这并没有真正破坏对象”的说法有点误导。它有点暗示它有点或有点破坏了对象。它根本不会破坏它。
  • 好的,我 /*编辑*/ 我更改的部分。那个更好吗?所以我需要两行来销毁对象,一行用于取消订阅委托/事件,另一行用于取消引用 GC 的对象?对吗?
  • @Enigmativity 对,在第一个循环后调用析构函数,但在第二个循环后释放对象。我混淆了一些东西。
【解决方案2】:

既然不能手动调用析构函数,为什么不实现IDisposable接口,在Dispose方法中执行注销呢?=!

public class testdelegate : IDisposable
{
    public delegate void del_copysomething(int newvaluetocopy);
    internal static del_copysomething dl_myfunctionthatcopy;
    public int valueforallobject = 0;

    public testdelegate()//ctor
    {
        dl_myfunctionthatcopy += new del_copysomething(copythisint);
    }
    private void copythisint(int newvalue)
    {
        valueforallobject = newvalue;
        Console.WriteLine("Copied");
    }

    public void Dispose()
    {
        dl_myfunctionthatcopy -= new del_copysomething(copythisint);
        GC.SuppressFinalize(this);
    }
}

DestroyObject_Click 方法中,您只需调用Dispose 方法:

private void DestroyObject_Click(object sender, EventArgs e)
{   //call Dispose destroy object
    thisdelegatetest.Dispose();
}

【讨论】:

  • 非常感谢大家!!
  • @Jablonovo 我猜它有效,我还没有测试过。很高兴我能帮忙
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2016-10-26
  • 2012-05-31
  • 1970-01-01
  • 1970-01-01
  • 2011-01-28
  • 1970-01-01
  • 2017-05-23
相关资源
最近更新 更多