C#::何时使用事件或从事件处理接口派生的对象集合? [英] C#:: When to use events or a collection of objects derived from an event handling Interface?

查看:242
本文介绍了C#::何时使用事件或从事件处理接口派生的对象集合?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我有我认为是一个简单的问题,我找到了几个解决方案,但我不知道哪种方式去和C的最佳实践。



在应用程序的生命周期中,我有一个主对象(例如单例)。这个MasterClass创建了一堆新类型的对象,每次调用MasterClass.Instance.CreateSlaveObject时都会说SlaveClass。



这个MasterClass还监视一些其他对象状态变化,当发生这种情况时,通知它创建的SlaveClass对象的变化。看起来很简单。



由于我来自本地C ++世界,我首先要做的是有一个接口

 接口IChangeEventListener 
{
void ChangeHappened();
}

我从中导出SlaveClass。然后在我的MasterClass我有:

  ... 
IList< IChangeEventListener> slaveList;
...
CreateSlaveObject
{
...
slaveList.Add(slave);
}
...
ChangeHappened()
{
...
foreach(slave中的var slave)
{
slave.ChangeHappened();
}
}

但我一直想知道,如果有另一个(更好的)这样做的想法。因此,我对这个话题进行了更多的研究,并看到了C#事件。



因此,不是保持MasterClass中的一个从属集合,我基本上将MasterClass注入ctor of SlaveClass(或通过属性),并让SlaveClass对象将它的ChangeHappened添加为事件处理程序。这将被说明:

  ... Master ... 
public delegate void ChangeHappenedDelegate(object sender,NewsInfoArgs args );
public event NewUpdateDelegate ChangeHappenedEvent;
....

public SlaveClass(MasterClass publisher)//注入发布服务
{
publisher.ChangeHappenedEvent + = ChangeHappened;
}

但这似乎是一个不必要的耦合从Master,但我喜欢所提供的内置事件通知机制的优雅。



我应该保留我当前的代码,或者移动到基于事件的方法注射)?为什么?



或者,如果你可以提出一个替代解决方案,我可能已经错过了,我也很感激。

sides 。



我认为活动的方式是我需要订阅你的活动,因为我需要你告诉我什么时候发生在你身上。



接口的方式是我需要调用一个方法告诉你发生了什么事情。
$ b

听起来是一样的,但不同的是谁在说话,在这两种情况下,它是你的大师班,正在说话,这使得所有的区别。



请注意,如果你的从类有一个方法可用于调用当你的主类发生了什么,你不需要从类包含代码来钩住这个,你可以在CreateSlaveClass方法中轻松地做到这一点:

  SlaveClass sc = new SlaveClass 
ChangeHappenedEvent + = sc.ChangeHappened;
return sc;

这将基本上使用事件系统,但让MasterClass代码执行事件的所有接线。



SlaveClass对象是否与singleton类一样长?如果没有,那么你需要处理这种情况,当他们变得陈旧/不再需要,如在上面的情况(基本上在你的和我的),你持有对你的MasterClass中的那些对象的引用,因此他们将永远不会有资格进行垃圾回收,除非你强制删除这些事件或取消注册接口。






SlaveClass不像MasterClass一样生活,你会遇到相同的耦合问题,正如你在注释中指出的那样。



一种方法是 (注意引号),这可能不是真的直接链接到SlaveClass对象上的正确方法,而是创建一个包装器对象,在内部将调用此方法。这样做的好处是,包装器对象可以在内部使用WeakReference对象,所以一旦你的SlaveClass对象有资格进行垃圾收集,它可能被收集,然后下一次尝试调用它正确的方法,你会注意到这一点,因此你必须清理。



例如,像这样(这里我打字没有Visual Studio intellisense和编译器,请采取这个代码的意义,而不是语法(错误)。)

  public class WrapperClass 
{
private WeakReference _Slave;

public WrapperClass(SlaveClass slave)
{
_Slave = new WeakReference(slave);
}

public WrapperClass.ChangeHappened()
{
Object o = _Slave.Target;
if(o!= null)
((SlaveClass)o).ChangeHappened();
else
MasterClass.ChangeHappenedEvent - = ChangeHappened;
}
}

在您的MasterClass中, :

  SlaveClass sc = new SlaveClass(); 
WrapperClass wc = new WrapperClass(s​​c);
ChangeHappenedEvent + = wc.ChangeHappened;
return sc;

一旦SlaveClass对象被收集,下一次调用(但不会早于)从你的MasterClass到事件处理程序通知他们更改,所有不再有对象的包装器将被删除。


I have what I think is a simple "problem" to which I have found a couple of solutions but I am not sure which way to go andn the best practice in C#.

I have a master object (say a singleton) instanciated once during the lifespan of the application. This "MasterClass" creates a bunch of new type of objects, say "SlaveClass" every time MasterClass.Instance.CreateSlaveObject is called.

This MasterClass also monitors some other object for status change, and when that happens, notifies the SlaveClass objects it created of the change. Seems simple enough.

Since I come from the native C++ world, the way I did it first it to have an interface

Interface IChangeEventListener
{
    void ChangeHappened();
}

from which I derived "SlaveClass". Then in my "MasterClass" i have:

...
IList<IChangeEventListener> slaveList;
...
CreateSlaveObject
{
    ...
    slaveList.Add(slave);
}
...
ChangeHappened()
{
    ...
    foreach(var slave in slaveList)
    {
       slave.ChangeHappened();
    }
}

And this works. But I kept wondering in the back of my mind if there is another (better) way of doing this. So I researched a bit more on the topic and saw the C# events.

So instead of maintaining a collection of slaves in the MasterClass, I would basically inject the MasterClass into the ctor of SlaveClass (or via a property) and let the SlaveClass object add it's ChangeHappened as an event handler. this would be illustrated:

  ...Master...          
  public delegate void ChangeHappenedDelegate(object sender, NewsInfoArgs args);
  public event NewUpdateDelegate ChangeHappenedEvent;
  ....

  public SlaveClass (MasterClass publisher) //inject publisher service
  {
      publisher.ChangeHappenedEvent += ChangeHappened;
  }

But this seems to be like an un-necessary coupling between the Slave and the Master, but I like the elegance of the provided build-in event notification mechanism.

So should I keep my current code, or move to the event based approach (with publisher injection)? and why?

Or if you can propose an alternative solution I might have missed, I would appreciate that as well.

解决方案

Well, in my mind, events and interfaces like you showed are two sides of the same coin (at least in the context you described it), but they're really two sides of this.

The way I think about events is that "I need to subscribe to your event because I need you to tell me when something happens to you".

Whereas the interface way is "I need to call a method on you to inform you that something happened to me".

It can sound like the same, but it differs in who is talking, in both cases it is your "masterclass" that is talking, and that makes all the difference.

Note that if your slave classes have a method available that would be suitable for calling when something happened in your master class, you don't need the slave class to contain the code to hook this up, you can just as easily do this in your CreateSlaveClass method:

SlaveClass sc = new SlaveClass();
ChangeHappenedEvent += sc.ChangeHappened;
return sc;

This will basically use the event system, but let the MasterClass code do all the wiring of the events.

Does the SlaveClass objects live as long as the singleton class? If not, then you need to handle the case when they become stale/no longer needed, as in the above case (basically in both of yours and mine), you're holding a reference to those objects in your MasterClass, and thus they will never be eligible for garbage collection, unless you forcibly remove those events or unregisters the interfaces.


To handle the problem with the SlaveClass not living as long as the MasterClass, you're going to run into the same coupling problem, as you also noted in the comment.

One way to "handle" (note the quotes) this could be to not really link directly to the correct method on the SlaveClass object, but instead create a wrapper object that internally will call this method. The benefit from this would be that the wrapper object could use a WeakReference object internally, so that once your SlaveClass object is eligible for garbage collection, it might be collected, and then the next time you try to call the right method on it, you would notice this, and thus you would have to clean up.

For instance, like this (and here I'm typing without the benefit of a Visual Studio intellisense and a compiler, please take the meaning of this code, and not the syntax (errors).)

public class WrapperClass
{
    private WeakReference _Slave;

    public WrapperClass(SlaveClass slave)
    {
        _Slave = new WeakReference(slave);
    }

    public WrapperClass.ChangeHappened()
    {
        Object o = _Slave.Target;
        if (o != null)
            ((SlaveClass)o).ChangeHappened();
        else
            MasterClass.ChangeHappenedEvent -= ChangeHappened;
    }
}

In your MasterClass, you would thus do something like this:

SlaveClass sc = new SlaveClass();
WrapperClass wc = new WrapperClass(sc);
ChangeHappenedEvent += wc.ChangeHappened;
return sc;

Once the SlaveClass object is collected, the next call (but not sooner than that) from your MasterClass to the event handlers to inform them of the change, all those wrappers that no longer has an object will be removed.

这篇关于C#::何时使用事件或从事件处理接口派生的对象集合?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆