C #: Tăng sự kiện kế thừa


144

Tôi có một lớp cơ sở chứa các sự kiện sau:

public event EventHandler Loading;
public event EventHandler Finished;

Trong một lớp kế thừa từ lớp cơ sở này, tôi cố gắng nâng cao sự kiện:

this.Loading(this, new EventHandler()); // All we care about is which object is loading.

Tôi nhận được lỗi sau:

Sự kiện 'BaseClass.Loading' chỉ có thể xuất hiện ở phía bên trái của + = hoặc - = (BaseClass ')

Tôi cho rằng tôi không thể truy cập các sự kiện này giống như các thành viên được kế thừa khác?


Câu hỏi này đã được trả lời bởi Frederik Gheysels . Cách làm tương tự được khuyến nghị trên Microsoft Docs: Cách nâng cao các sự kiện của lớp cơ sở trong các lớp dẫn xuất (Hướng dẫn lập trình C #) như một "Hướng dẫn lập trình C #" chính thức
Eliahu Aaron

Câu trả lời:


160

Những gì bạn phải làm, là đây:

Trong lớp cơ sở của bạn (nơi bạn đã khai báo các sự kiện), tạo các phương thức được bảo vệ có thể được sử dụng để nâng cao các sự kiện:

public class MyClass
{
   public event EventHandler Loading;
   public event EventHandler Finished;

   protected virtual void OnLoading(EventArgs e)
   {
       EventHandler handler = Loading;
       if( handler != null )
       {
           handler(this, e);
       }
   }

   protected virtual void OnFinished(EventArgs e)
   {
       EventHandler handler = Finished;
       if( handler != null )
       {
           handler(this, e);
       }
   }
}

(Lưu ý rằng có lẽ bạn nên thay đổi các phương thức đó, để kiểm tra xem bạn có phải gọi Eventhandler hay không).

Sau đó, trong các lớp kế thừa từ lớp cơ sở này, bạn chỉ có thể gọi các phương thức OnFinished hoặc OnLoading để nâng cao các sự kiện:

public AnotherClass : MyClass
{
    public void DoSomeStuff()
    {
        ...
        OnLoading(EventArgs.Empty);
        ...
        OnFinished(EventArgs.Empty);
    }
}

5
Những phương thức đó nên được bảo vệ ảo trừ khi có một số lý do để làm khác.
Tối đa

6
Tại sao nó phải là ảo? Tôi sẽ tuyên bố nó là ảo nếu tôi muốn những người thừa kế thay đổi cách tổ chức sự kiện, nhưng hầu hết thời gian, tôi thấy không có lý do gì để làm điều này ...
Frederik Gheysels


5
Về việc làm cho phương thức trở nên ảo, để những người thừa kế có thể ghi đè hành vi gọi sự kiện: Bạn đã bao nhiêu lần trong tình huống cần thiết? Bên cạnh đó; trong phương pháp overriden, bạn không thể nêu ra sự kiện, vì bạn sẽ gặp lỗi tương tự như lỗi được đề cập bởi TS.
Frederik Gheysels

2
@Verax Tôi làm theo vì lý do là hợp lý, tùy thuộc vào mức độ có thể sử dụng lại và mở rộng mà tôi mong đợi mã này, tôi đã cung cấp các hướng dẫn chính thức để sao lưu .. tại thời điểm viết bạn cũng có vẻ rất mới đối với .NET Verax Vì vậy, có một chút bối rối khi bạn đào cái này lên để không đồng ý với 7 năm kinh nghiệm của tôi
meandmycode

123

Bạn chỉ có thể truy cập một sự kiện trong lớp khai báo, vì .NET tạo các biến cá thể riêng tư đằng sau các cảnh thực sự giữ đại biểu. Làm điều này ..

public event EventHandler MyPropertyChanged;

đang thực sự làm điều này;

private EventHandler myPropertyChangedDelegate;

public event EventHandler MyPropertyChanged
{
    add { myPropertyChangedDelegate += value; }
    remove { myPropertyChangedDelegate -= value; }
}

và làm điều này ...

MyPropertyChanged(this, EventArgs.Empty);

thực ra đây là ...

myPropertyChangedDelegate(this, EventArgs.Empty);

Vì vậy, bạn có thể (rõ ràng) chỉ truy cập vào biến đối tượng ủy nhiệm riêng từ bên trong lớp khai báo.

Quy ước là cung cấp một cái gì đó như thế này trong lớp khai báo ..

protected virtual void OnMyPropertyChanged(EventArgs e)
{
    EventHandler invoker = MyPropertyChanged;

    if(invoker != null) invoker(this, e);
}

Sau đó, bạn có thể gọi OnMyPropertyChanged(EventArgs.Empty)từ bất cứ nơi nào trong lớp đó hoặc bên dưới quyền thừa kế thừa kế để gọi sự kiện.


Tôi đã gặp một số vấn đề khi thực hiện điều này ... stackoverflow.com/q/10593632/328397
goodguys_activate

Tôi thích câu trả lời này vì nó giải thích TẠI SAO bạn phải sử dụng cách tiếp cận thay vì chỉ tiếp cận. Công việc tốt đẹp.
cowboydan

8

Tôi cho rằng tôi không thể truy cập các sự kiện này giống như các thành viên được kế thừa khác?

Đúng. Đó là thông lệ để cung cấp một chức năng được bảo vệ OnXyzhoặc RaiseXyzcho từng sự kiện trong lớp cơ sở để cho phép nâng cao từ các lớp được kế thừa. Ví dụ:

public event EventHandler Loading;

protected virtual void OnLoading() {
    EventHandler handler = Loading;
    if (handler != null)
        handler(this, EventArgs.Empty);
}

Được gọi trong lớp kế thừa:

OnLoading();

0

Bạn có thể thử theo cách này, Nó hoạt động với tôi:

public delegate void MyEventHaldler(object sender, EventArgs e);

public class B
{
    public virtual event MyEventHaldler MyEvent;
    protected override void OnChanged(EventArgs e)
    {
        if (MyEvent != null)
            MyEvent(this, e);
    }
}

public class D : B
{
    public override event MyEventHaldler MyEvent;
    protected override void OnChanged(EventArgs e)
    {
        if (MyEvent != null)
            MyEvent(this, e);
    }
}

2
Lưu ý rằng bài viết này cảnh báo chống lại việc khai báo các sự kiện ảo và ghi đè chúng vì nó tuyên bố trình biên dịch không xử lý chính xác điều này: msdn.microsoft.com/en-us/l Library / ry3sefw3.aspx
mạng không dây công cộng

0

không phải để hồi sinh một chủ đề cũ nhưng trong trường hợp bất cứ ai đang tìm kiếm, những gì tôi đã làm là

protected EventHandler myPropertyChangedDelegate;

public event EventHandler MyPropertyChanged
{
    add { myPropertyChangedDelegate += value; }
    remove { myPropertyChangedDelegate -= value; }
}

Điều này cho phép bạn kế thừa sự kiện trong một lớp dẫn xuất để bạn có thể gọi nó mà không cần phải bọc phương thức trong khi vẫn giữ cú pháp + =. Tôi đoán bạn vẫn có thể làm điều đó với các phương pháp gói nếu bạn đã làm

public event EventHandler MyPropertyChanged
{
   add { AddDelegate(value); }
   remove { RemoveDelegate(value); }
}
Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.