3

我经常遇到一种情况,我必须决定在哪里订阅内部对象的事件?

例如,我有一个对象模型如下所示:

class ClassA
{
    public event EventHandler SomeEvent1;
    public event EventHandler SomeEvent2;
    public event EventHandler SomeEvent3;
    public event EventHandler SomeEvent4;
}

class ClassB
{
    private ClassA a;
    public ClassA A 
    {
        get
        {
            return this.a;
        }
    }

    public ClassB()
    {
        this.a = new ClassA();
        // here subscribe to some events (for example, SomeEvent1 and SomeEvent2)
        // this.a.SomeEvent1 += OnSomeEvent1Raised;
        // this.a.SomeEvent2 += OnSomeEvent2Raised;
    }
}

class ClassC
{
    public ClassB B { get; }
}

class ClassD
{
    public ClassC C { get; }

    public void SomeMethod()
    {
        // Here subscribe to another ones events of object C.B.A. For example:
        C.B.A.SomeEvent3 += OnSomeEvent3Raised;
        C.B.A.SomeEvent4 += OnSomeEvent4Raised;
    }

    private void OnSomeEvent4Raised(object sender, EventArgs e)
    {
        throw new NotImplementedException();
    }

    private void OnSomeEvent3Raised(object sender, EventArgs e)
    {
        throw new NotImplementedException();
    }
}

我试图创建类似 UML 图的东西: 在此处输入图像描述

我的项目的现有代码的结构具有存在此类对象模型的位置(它具有订阅如上例中实现的事件的位置 - CBASomeEvent+= )。我不喜欢它,想改变它。我想从你这里得到关于这种情况的最佳实践。

另一种方法是在classB、classC、classD中复制classA的所有事件。然后将所有对事件的订阅替换为ONE PLACE(我的意思是,在 B 类中,我们将订阅/取消订阅 A 类对象的所有事件。在 C 类中,我们将订阅/取消订阅 B 类对象的所有事件。所以on...) 在这种情况下,所有订阅和取消订阅都将集中在一个地方。希望,你明白我在这里的意思。

再次,请依靠您的知识和经验告诉我们如何解决这种情况。

更新

您是否同意我的订阅和取消订阅事件必须放在一个地方?请也回答这个附加问题。

提前致谢。

4

3 回答 3

2

您可能对事件聚合器感兴趣。

它基本上所做的是将发布者与订阅者分离——它是一种事件容器。您可以通过依赖注入(例如 MEF)为您想要订阅或发布的每个类获取事件聚合器。

我个人使用并且最喜欢它的方式是 Rob Eisenberg 在 Caliburn Micro 中实现事件聚合器的方式:

在您的情况下,对象 A、B 和 C 将共享事件聚合器的同一实例,这意味着一旦事件在此事件聚合器上发布,所有这些对象都会识别它。由于对某些事件的不同处理,A、B 和 C 类能够表现不同。

编辑

事件聚合器的用途是,您使用类的实例订阅聚合器本身。发布者和订阅者类之间的连接是通过依赖事件聚合器的同一实例来实现的。如果 Caliburn.Micro 通过实现通用接口 ( IHandle<>) 订阅某些事件。例如:如果您想订阅,则在要订阅的类中MyCustomEvent实现IHandle<MyCustomEvent>接口。这需要从此类事件void Handle(MyCustomEvent e)的接口实现方法。IHandle<MyCustomEvent>每次MyCustomEvent在共享事件聚合器上发布(新)时都会调用此方法。

于 2013-01-23T12:41:07.807 回答
0

您的示例中有太多public内容。希望我会在下面有意义:

  1. ClassB 包含一个 ClassA 类型的对象,并处理一些 ClassA 事件
  2. ClassC 包含 ClassB 类型的对象,但事件被忽略。
  3. ClassD 包含一个 ClassC 类型的对象,并处理来自 ClassB 对象内的 ClassA 对象的事件,该对象包含在此 ClassC 对象中

#2 和 #3 不好:ClassC 应该处理和实现事件,处理它们并让它们“冒泡”(调用它们自己的、相同的事件)以便 ClassD 正确处理。

基本上,它们都应该处理所有事件,要么对它们做出反应(如在 ClassB 中对 ClassA 的事件),要么只是传播它们。

于 2013-01-23T13:28:10.427 回答
0

在这里找到不错的解决方案:

Csharp-通知中心

于 2013-01-27T16:19:15.867 回答