2015-08-03 4 views
3

У меня есть следующий сценарий:Вызов события из базового класса

public abstract class SomeBaseClass 
{ 
    public event EventHandler SomeEvent; 

    ... 
} 

public class SomeClass : SomeBaseClass 
{ 
    public void DoSomething() 
    { 
     //TODO 

     if (SomeEvent != null) 
      SomeEvent(this, EventArgs.Empty); 
    } 
} 

SomeBaseClass имеет событие, которое необходимо, чтобы называться в базовом классе, однако это не представляется возможным непосредственно вызывать событие из базовый класс. Чтобы обойти эту проблему, я могу переопределить событие в базовом классе, например, так:

public class SomeClass : SomeBaseClass 
{ 
    new public event EventHandler SomeEvent; 

Это нормально, я предполагаю, однако мой вопрос, есть ли какой-то универсальный метод, или хорошая практика для реализовать функциональность выше?

Тот факт, что невозможно назвать событие из базового класса, предполагает, что я не должен делать это в первую очередь, возможно, ответственность за вызов события должна быть только в SomeBaseClass?

+1

вы пытались 'SomeEvent (база, EventArgs.Empty);'? –

+1

AFAIK, события не наследуются, поэтому вы не можете поднять событие непосредственно из производного класса, но вы можете написать защищенный метод в родительском классе, который поднимет событие при вызове и вызовет его из производного класса, используя ' base.RaiseMyEvent (new EventArgs()) ' –

+1

@KhanhTO Да, я получил ошибку: *« Использование ключевого слова «base» недопустимо в этом контексте * « –

ответ

6

Это действительно не допускается. Если я могу рекомендовать альтернативный подход:

public abstract class SomeBaseClass 
{ 
    public event EventHandler SomeEvent; 

    protected void RaiseSomeEvent(EventArgs e) 
    { 
     var eh = SomeEvent; 
     if (eh != null) 
      eh(this, e); 
    } 
} 

public class SomeClass : SomeBaseClass 
{ 
    public void DoSomething() 
    { 
     //TODO 
     RaiseSomeEvent(EventArgs.Empty); 
    } 
} 

Обратите внимание, что я переместил вызов обработчика событий для имущего класса, это требуется .NET/C#, так как только этот класс может вызывать обработчик события. Во-вторых, я сделал безопасный поток обработчика событий, назначив его eh.

Никогда спрятать событие базового класса с помощью ключевого слова new! Вы получите неожиданные результаты, когда используете тип базового класса как тип для переменной или когда базовый класс вызывает событие.

+3

В [C# 6.0] (https://github.com/dotnet/roslyn/wiki/New-Language-Features-in-C% 23-6 # null-условные-операторы) потокобезопасное событие растет «просто» 'SomeEvent ?.Invoke (this, e);' – Sinatr

+0

@Sinatr, что действительно приятно. Спасибо за полезный комментарий. –

2

Я бы держался подальше от использования new в основном потому, что код будет вести себя по-другому, если объект будет передан базовому классу. Вот альтернативная реализация:

public abstract class SomeBaseClass 
{ 
    public virtual event EventHandler SomeEvent; 

    protected virtual void HandleSomeEvent() 
    { 
     var ev = SomeEvent; // Localize event field used 
     if (ev != null) 
     { 
      ev(this, EventArgs.Empty); 
     } 
    } 
} 

public class SomeClass : SomeBaseClass 
{ 
    public override event EventHandler SomeEvent 
    { 
     add { base.SomeEvent += value; } 
     remove { base.SomeEvent -= value; } 
    } 

    protected override void HandleSomeEvent() 
    { 
     base.HandleSomeEvent(); 
     // ... My own code here 
    } 
} 

Это позволяет проявлять большую гибкость. Вы можете обеспечить некоторую реализацию обработки событий, а также позволить разработчику полностью переопределить реализацию базового класса.

0

Я лично предпочитаю использовать делегатов для этого:

public abstract class SomeBaseClass 
    { 
     public event EventHandler SomeEvent; 
     protected Action<object, EventArgs> SomeEventInvoker; 

     public SomeBaseClass() 
     { 
      SomeEventInvoker = new Action<object, EventArgs>((sender, args) => 
      { if (SomeEvent != null) SomeEvent(sender, args); }); 
     } 
    } 

    public class SomeClass : SomeBaseClass 
    { 
     public SomeClass() 
     { 
      DoSomething(); 
     } 

     public void DoSomething() 
     {     
      SomeEventInvoker(this, new EventArgs()); 
     } 
    } 
Смежные вопросы