需要一条面向对象编程技巧

3
我希望有一个抽象类,可以触发一个事件,这个事件将由具体的类来触发。
我的需求是当我使用另一个类来监听这些事件时,委托的签名应该是具体类型而不是抽象类型,我不想强制转换它。
目前,我想到了这个解决方案。它能够工作,但我觉得它并不特别聪明,特别是因为其中的“愚蠢,没有意义......”部分。
以下是我的解决方案:
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();
    }   
    */
}

1
不清楚你在这里尝试解决什么问题。你已经将范围缩小到一个父级“抽象类引发事件”,但为什么? - beautifulcoder
1个回答

2

首先,你没有遵循.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

谢谢!这正是我想要做的(显然是用错误的方式)。 - OopMagik

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接