需要一个面向对象的技巧

本文关键字:一个 面向对象的 | 更新日期: 2023-09-27 18:08:42

我想要一个引发事件的抽象类,这个事件将由具体类引发。

我想要的是当我使用另一个类来监听这些事件时,委托的签名应该具有具体类型而不是抽象类型,我不想强制转换它。

目前我已经想出了这个解决方案。它是有效的,但我不觉得它特别聪明,特别是因为"愚蠢,没有意义......"的部分。

这是我的解决方案:

public delegate void ClassAEventHandler<TClassA>(TClassA classA) where TClassA : ClassA;
//Abstract class that raise Event
public abstract class ClassA<TClassA> : where TClassA : ClassA
{
    public event ClassAEventHandler<TClassA> onClassEventRaised;    
    private TClassA eventClassA;
    public void registerEventClass(TClassA classA)
    {
        this.eventClassA = classA;
    }
    public void raiseClassEvent()
    {
        this.onClassEventRaised(this.eventClassA);
    }
}
// Exemple of concrete type
public class ClassB : ClassA<ClassB> // <------ IT SEEMS DUMB
{
    public void action()
    {
        //Do something then raise event
        this.raiseClassEvent();
    }
    public void saySomething() {};
}
// Exemple of concrete type
public class ClassC : ClassA<ClassC> // <------ IT SEEMS DUMB
{
    public void command()
    {
        //Do something then raise event
        this.raiseClassEvent();
    }
    public void destroySomething() {};
}
//Class that listen to the event raised
public class MyEventListener
{
    private ClassB classB;
    private ClassC classC;
    public MyEventListener()
    {
        this.classB = new ClassB();
        this.classB.registerEventClass(this.classB); // <------ STUPID, DOESN'T MAKE SENSE......
        this.classB.onClassEventRaised += classB_onClassEventRaised;
        this.classC = new ClassC();
        this.classC.registerEventClass(this.classC); // <------ STUPID, DOESN'T MAKE SENSE......
        this.classC.onClassEventRaised += classC_onClassEventRaised;
    }
    public void classB_onClassEventRaised(ClassB classB)
    {
        classB.saySomething();
    }
    public void classC_onClassEventRaised(ClassC classC)
    {
        classC.destroySomething();
    }
    //What i don't want
    /*
    public void classB_onClassEventRaised(ClassA classA)
    {
        ((classB)classA).saySomething();
    }   
    */
}

需要一个面向对象的技巧

首先,您没有遵循。net中的常规事件设计。

不要实现自己的委托,而是使用EventHandler<TArgs>,并创建EventArgs的派生类。

您的CustomEventArgs应该有一个T通用参数:

public class CustomEventArgs<T> where T : A
{
     private readonly T _instance;
     public CustomEventArgs(T instance)
     {
          _instance = instance;
     }
     public T Instance { get { return _instance; } }
}

另外,不要实现自定义的方式来注册事件。如果您想封装如何将处理程序添加到事件,则需要使用事件访问器

最后,你可以这样实现你的类:

public class A<T> where T : A
{
     private event EventHandler<CustomEventArgs<T>> _someEvent;
     // An event accessor acts like the event but it can't be used
     // to raise the event itself. It's just an accessor like an special
     // event-oriented property (get/set)
     public event EventHandler<CustomEventArgs<T>> SomeEvent
     {
          add { _someEvent += value; }
          remove { _someEvent -= value; }
     }
     protected virtual void RaiseSomeEvent(CustomEventArgs<T> args)
     {
           // If C# >= 6
           _someEvent?.Invoke(this, args);
           // Or in C# < 6
           // if(_someEvent != null) _someEvent(this, args);
     }
}

public class B : A<B> 
{ 
      public void DoStuff()
      {
           // It's just about raising the event accessing the whole
           // protected method and give an instance of CustomEventArgs<B> 
           // passing current instance (i.e. this) to CustomEventArgs<T>
           // constructor.
           RaiseSomeEvent(new CustomEventArgs<B>(this));
      }
}

现在,如果您尝试处理SomeEvent,您将得到CustomEventArgs<B>类型为B而不是A:

B b = new B();
b.SomeEvent += (sender, args) =>
{
    // args.Instance is B
    B instance = args.Instance;
};
b.DoStuff(); // Raises SomeEvent internally