C# Action 委托 为什么只响应一次啊?

wushang923 2016-03-05 11:26:30

public static class ActionHelper
{
public static Action TestAction;
}

public class ReceiveA
{
public ReceiveA()
{
ActionHelper.TestAction = TestAction;
}

private void TestAction()
{
MessageBox.Show("A");
}
}

public class ReceiveB
{
public ReceiveB()
{
ActionHelper.TestAction = TestAction;
}

private void TestAction()
{
MessageBox.Show("B");
}
}


调用:

private void ActonTestBtn_Click(object sender, EventArgs e)
{
ReceiveA receiveA = new ReceiveA();
ReceiveB receiveB = new ReceiveB();
if (ActionHelper.TestAction != null)
{
ActionHelper.TestAction();
}
}


如上代码只能弹出“B”的提示框,A的没执行,如果A的实例化在B后面结果就相反。如果也就是只执行了后面一个,请问为什么会这样啊?如果我想两个都接收到该怎么处理啊?

测试了一下delegate可以......WHY?
...全文
342 8 打赏 收藏 转发到动态 举报
写回复
用AI写文章
8 条回复
切换为时间正序
请发表友善的回复…
发表回复
wushang923 2016-03-07
  • 打赏
  • 举报
回复
引用 5 楼 sp1234 的回复:
事件泄露问题,是会让应用程序占用的内存迅速滚雪球攀升,会让应用程序变得很慢、做了许多无用功(因为触发事件时调用了许多根本不应该调用的委托)。 这其实是个编程中的严重的问题,而且往往只能在运行时才在用户面前丢人现眼。在开发中也没有什么又能保证基本性能、又能简洁方便的好的方法来避免。这通常靠测试用例来判断是否存在泄露问题,例如在测试用例中先创建、显示一个窗体,并且使用 WeakReference 类型对象来关联它。然后关闭窗体,然后在10秒钟之后再来根据这个 WeakReference 对象来判断是否此窗体对象是否还“活着”。基本上可以保证在10秒钟之内,GC就应该销毁了多余的对象了,否则就是出现了泄露问题。
THKS,太感谢了。果然学艺不精啊。
Poopaye 2016-03-05
  • 打赏
  • 举报
回复
public static class ActionHelper { public static Action TestAction; } public class ReceiveA { public ReceiveA() { ActionHelper.TestAction += TestAction; } private void TestAction() { MessageBox.Show("A"); } } public class ReceiveB { public ReceiveB() { ActionHelper.TestAction += TestAction; } private void TestAction() { MessageBox.Show("B"); } }
  • 打赏
  • 举报
回复
事件泄露问题,是会让应用程序占用的内存迅速滚雪球攀升,会让应用程序变得很慢、做了许多无用功(因为触发事件时调用了许多根本不应该调用的委托)。 这其实是个编程中的严重的问题,而且往往只能在运行时才在用户面前丢人现眼。在开发中也没有什么又能保证基本性能、又能简洁方便的好的方法来避免。这通常靠测试用例来判断是否存在泄露问题,例如在测试用例中先创建、显示一个窗体,并且使用 WeakReference 类型对象来关联它。然后关闭窗体,然后在10秒钟之后再来根据这个 WeakReference 对象来判断是否此窗体对象是否还“活着”。基本上可以保证在10秒钟之内,GC就应该销毁了多余的对象了,否则就是出现了泄露问题。
  • 打赏
  • 举报
回复
区分“使用普通的委托、还是进一步升级为 event”是一个需要注意的编程设计知识。 除此以外,实际上按照上述的 ActionHelper 的定义来看,它就非常容易产生“事件泄露”的问题。因此通常要求写成
public class ReceiveA : IDisposable
{
    public ReceiveA()
    {
        ActionHelper.TestAction += TestAction;
    }

    public void Dispose()
    {
        ActionHelper.TestAction -= TestAction;
    }
........
并且要求显式用你的代码来调用 A 类对象实例的 Dispose 方法,例如放到 using(){...} 结构中。否则,可能就根本无法真正让 GC 去回收此类对象实例,因为
public static Action TestAction;
总是引用着它,无法释放。 反过来,也说明你使用 static Action TestAction 这个设计是有问题的、找麻烦的。
  • 打赏
  • 举报
回复
首先,对于 Delegate 来说,你可以使用 += 操作符。因为 Delegate 是可以一般化为 MulticastDelegate,例如
ActionHelper.TestAction += TestAction;
就是如此。 但是,你从中也就能看到了,任何一个外部类都能胡乱修改它。例如 A 使用了 +=,而B 还是原来的写法,则 A 中正常的 += 就代码自欺欺人地(而不是明明白白地)篡改了。所以实际上这通常写为
public static class ActionHelper
{
    public static event Action TestAction;

    public static void Go()
    {
        if (ActionHelper.TestAction != null)
        {
            ActionHelper.TestAction();
        }
    }
}
ReceiveA receiveA = new ReceiveA();
ReceiveB receiveB = new ReceiveB();
ActionHelper.Go();
这样,可以防止 ActionHelper 类以外的代码去(不小心)篡改它。
  • 打赏
  • 举报
回复
委托链了解下,不要用=号
  • 打赏
  • 举报
回复
因为 public static 只能有一个值。
tcmakebest 2016-03-05
  • 打赏
  • 举报
回复
如果只是用 = 赋值,当然只能保存一个值, delegate 是用 += 的,只是很小的区别

111,129

社区成员

发帖
与我相关
我的任务
社区描述
.NET技术 C#
社区管理员
  • C#
  • Creator Browser
  • by_封爱
加入社区
  • 近7日
  • 近30日
  • 至今
社区公告

让您成为最强悍的C#开发者

试试用AI创作助手写篇文章吧