需要一个OOP技巧

时间:2015-08-19 19:35:39

标签: c# oop

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

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

目前我已经提出了这个解决方案。它有效,但我发现它并不特别聪明,尤其是因为“愚蠢,愚蠢和感觉......”#34;一部分。

这是我的解决方案:

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 个答案:

答案 0 :(得分: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