結(jié)合.net框架在C#派生類(lèi)中觸發(fā)基類(lèi)事件及實(shí)現(xiàn)接口事件
在派生類(lèi)中引發(fā)基類(lèi)事件
以下簡(jiǎn)單示例演示了在基類(lèi)中聲明可從派生類(lèi)引發(fā)的事件的標(biāo)準(zhǔn)方法。此模式廣泛應(yīng)用于 .NET Framework 類(lèi)庫(kù)中的 Windows 窗體類(lèi)。
在創(chuàng)建可用作其他類(lèi)的基類(lèi)的類(lèi)時(shí),應(yīng)考慮如下事實(shí):事件是特殊類(lèi)型的委托,只可以從聲明它們的類(lèi)中調(diào)用。派生類(lèi)無(wú)法直接調(diào)用基類(lèi)中聲明的事件。盡管有時(shí)需要事件僅由基類(lèi)引發(fā),但在大多數(shù)情形下,應(yīng)該允許派生類(lèi)調(diào)用基類(lèi)事件。為此,您可以在包含該事件的基類(lèi)中創(chuàng)建一個(gè)受保護(hù)的調(diào)用方法。通過(guò)調(diào)用或重寫(xiě)此調(diào)用方法,派生類(lèi)便可以間接調(diào)用該事件。
注意:不要在基類(lèi)中聲明虛擬事件,也不要在派生類(lèi)中重寫(xiě)這些事件。C# 編譯器無(wú)法正確處理這些事件,并且無(wú)法預(yù)知的該派生的事件的用戶(hù)是否真正訂閱了基類(lèi)事件。
namespace BaseClassEvents { using System; using System.Collections.Generic; // Special EventArgs class to hold info about Shapes. public class ShapeEventArgs : EventArgs { private double newArea; public ShapeEventArgs(double d) { newArea = d; } public double NewArea { get { return newArea; } } } // Base class event publisher public abstract class Shape { protected double area; public double Area { get { return area; } set { area = value; } } // The event. Note that by using the generic EventHandler<T> event type // we do not need to declare a separate delegate type. public event EventHandler<ShapeEventArgs> ShapeChanged; public abstract void Draw(); //The event-invoking method that derived classes can override. protected virtual void OnShapeChanged(ShapeEventArgs e) { // Make a temporary copy of the event to avoid possibility of // a race condition if the last subscriber unsubscribes // immediately after the null check and before the event is raised. EventHandler<ShapeEventArgs> handler = ShapeChanged; if (handler != null) { handler(this, e); } } } public class Circle : Shape { private double radius; public Circle(double d) { radius = d; area = 3.14 * radius * radius; } public void Update(double d) { radius = d; area = 3.14 * radius * radius; OnShapeChanged(new ShapeEventArgs(area)); } protected override void OnShapeChanged(ShapeEventArgs e) { // Do any circle-specific processing here. // Call the base class event invocation method. base.OnShapeChanged(e); } public override void Draw() { Console.WriteLine("Drawing a circle"); } } public class Rectangle : Shape { private double length; private double width; public Rectangle(double length, double width) { this.length = length; this.width = width; area = length * width; } public void Update(double length, double width) { this.length = length; this.width = width; area = length * width; OnShapeChanged(new ShapeEventArgs(area)); } protected override void OnShapeChanged(ShapeEventArgs e) { // Do any rectangle-specific processing here. // Call the base class event invocation method. base.OnShapeChanged(e); } public override void Draw() { Console.WriteLine("Drawing a rectangle"); } } // Represents the surface on which the shapes are drawn // Subscribes to shape events so that it knows // when to redraw a shape. public class ShapeContainer { List<Shape> _list; public ShapeContainer() { _list = new List<Shape>(); } public void AddShape(Shape s) { _list.Add(s); // Subscribe to the base class event. s.ShapeChanged += HandleShapeChanged; } // ...Other methods to draw, resize, etc. private void HandleShapeChanged(object sender, ShapeEventArgs e) { Shape s = (Shape)sender; // Diagnostic message for demonstration purposes. Console.WriteLine("Received event. Shape area is now {0}", e.NewArea); // Redraw the shape here. s.Draw(); } } class Test { static void Main(string[] args) { //Create the event publishers and subscriber Circle c1 = new Circle(54); Rectangle r1 = new Rectangle(12, 9); ShapeContainer sc = new ShapeContainer(); // Add the shapes to the container. sc.AddShape(c1); sc.AddShape(r1); // Cause some events to be raised. c1.Update(57); r1.Update(7, 7); // Keep the console window open in debug mode. System.Console.WriteLine("Press any key to exit."); System.Console.ReadKey(); } } }
輸出:
Received event. Shape area is now 10201.86 Drawing a circle Received event. Shape area is now 49 Drawing a rectangle
實(shí)現(xiàn)接口事件
接口可聲明事件。下面的示例演示如何在類(lèi)中實(shí)現(xiàn)接口事件。實(shí)現(xiàn)接口事件的規(guī)則與實(shí)現(xiàn)任何接口方法或?qū)傩缘囊?guī)則基本相同。
在類(lèi)中實(shí)現(xiàn)接口事件
在類(lèi)中聲明事件,然后在適當(dāng)?shù)膮^(qū)域調(diào)用該事件。
namespace ImplementInterfaceEvents { public interface IDrawingObject { event EventHandler ShapeChanged; } public class MyEventArgs : EventArgs { // class members } public class Shape : IDrawingObject { public event EventHandler ShapeChanged; void ChangeShape() { // Do something here before the event… OnShapeChanged(new MyEventArgs(/*arguments*/)); // or do something here after the event. } protected virtual void OnShapeChanged(MyEventArgs e) { if(ShapeChanged != null) { ShapeChanged(this, e); } } } }
下面的示例演示如何處理以下的不常見(jiàn)情況:您的類(lèi)是從兩個(gè)以上的接口繼承的,每個(gè)接口都含有同名事件)。在這種情況下,您至少要為其中一個(gè)事件提供顯式接口實(shí)現(xiàn)。為事件編寫(xiě)顯式接口實(shí)現(xiàn)時(shí),必須編寫(xiě) add 和 remove 事件訪問(wèn)器。這兩個(gè)事件訪問(wèn)器通常由編譯器提供,但在這種情況下編譯器不能提供。
您可以提供自己的訪問(wèn)器,以便指定這兩個(gè)事件是由您的類(lèi)中的同一事件表示,還是由不同事件表示。例如,根據(jù)接口規(guī)范,如果事件應(yīng)在不同時(shí)間引發(fā),則可以將每個(gè)事件與類(lèi)中的一個(gè)單獨(dú)實(shí)現(xiàn)關(guān)聯(lián)。在下面的示例中,訂戶(hù)將形狀引用強(qiáng)制轉(zhuǎn)換為 IShape 或 IDrawingObject,從而確定自己將會(huì)接收哪個(gè) OnDraw 事件。
namespace WrapTwoInterfaceEvents { using System; public interface IDrawingObject { // Raise this event before drawing // the object. event EventHandler OnDraw; } public interface IShape { // Raise this event after drawing // the shape. event EventHandler OnDraw; } // Base class event publisher inherits two // interfaces, each with an OnDraw event public class Shape : IDrawingObject, IShape { // Create an event for each interface event event EventHandler PreDrawEvent; event EventHandler PostDrawEvent; object objectLock = new Object(); // Explicit interface implementation required. // Associate IDrawingObject's event with // PreDrawEvent event EventHandler IDrawingObject.OnDraw { add { lock (objectLock) { PreDrawEvent += value; } } remove { lock (objectLock) { PreDrawEvent -= value; } } } // Explicit interface implementation required. // Associate IShape's event with // PostDrawEvent event EventHandler IShape.OnDraw { add { lock (objectLock) { PostDrawEvent += value; } } remove { lock (objectLock) { PostDrawEvent -= value; } } } // For the sake of simplicity this one method // implements both interfaces. public void Draw() { // Raise IDrawingObject's event before the object is drawn. EventHandler handler = PreDrawEvent; if (handler != null) { handler(this, new EventArgs()); } Console.WriteLine("Drawing a shape."); // RaiseIShape's event after the object is drawn. handler = PostDrawEvent; if (handler != null) { handler(this, new EventArgs()); } } } public class Subscriber1 { // References the shape object as an IDrawingObject public Subscriber1(Shape shape) { IDrawingObject d = (IDrawingObject)shape; d.OnDraw += new EventHandler(d_OnDraw); } void d_OnDraw(object sender, EventArgs e) { Console.WriteLine("Sub1 receives the IDrawingObject event."); } } // References the shape object as an IShape public class Subscriber2 { public Subscriber2(Shape shape) { IShape d = (IShape)shape; d.OnDraw += new EventHandler(d_OnDraw); } void d_OnDraw(object sender, EventArgs e) { Console.WriteLine("Sub2 receives the IShape event."); } } public class Program { static void Main(string[] args) { Shape shape = new Shape(); Subscriber1 sub = new Subscriber1(shape); Subscriber2 sub2 = new Subscriber2(shape); shape.Draw(); // Keep the console window open in debug mode. System.Console.WriteLine("Press any key to exit."); System.Console.ReadKey(); } } }
輸出:
Sub1 receives the IDrawingObject event. Drawing a shape. Sub2 receives the IShape event.
- C#中的應(yīng)用程序接口介紹及實(shí)現(xiàn),密封類(lèi)與密封方法
- .NET/C#如何判斷某個(gè)類(lèi)是否是泛型類(lèi)型或泛型接口的子類(lèi)型詳解
- C# WebApi 接口返回值不困惑:返回值類(lèi)型詳解
- C#中抽象類(lèi)與接口的區(qū)別詳解
- C#接口在派生類(lèi)和外部類(lèi)中的調(diào)用方法示例
- 深入解析C#中的泛型類(lèi)與泛型接口
- C#中類(lèi)與接口的區(qū)別個(gè)人總結(jié)
- C#中實(shí)現(xiàn)判斷某個(gè)類(lèi)是否實(shí)現(xiàn)了某個(gè)接口
- C#抽象類(lèi)和接口的區(qū)別分析
- 解析在C#中接口和類(lèi)的異同
相關(guān)文章
輕松學(xué)習(xí)C#的foreach迭代語(yǔ)句
輕松學(xué)習(xí)C#的foreach迭代語(yǔ)句, C#語(yǔ)言提供了一個(gè)for語(yǔ)句循環(huán)的捷徑,而且還促進(jìn)了集合類(lèi)的更為一致,就是本文提到的foreach語(yǔ)句,感興趣的小伙伴們可以參考一下2015-11-11unity3D實(shí)現(xiàn)攝像機(jī)抖動(dòng)特效
這篇文章主要為大家詳細(xì)介紹了unity3D實(shí)現(xiàn)攝像機(jī)抖動(dòng)特效,文中示例代碼介紹的非常詳細(xì),具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下2020-01-01C#環(huán)形緩沖區(qū)(隊(duì)列)完全實(shí)現(xiàn)
這篇文章主要為大家詳細(xì)介紹了C#環(huán)形緩沖區(qū)(隊(duì)列)完全實(shí)現(xiàn)代碼,感興趣的小伙伴們可以參考一下2016-07-07C#實(shí)現(xiàn)大數(shù)字運(yùn)算的實(shí)例代碼
這篇文章介紹了C#實(shí)現(xiàn)大數(shù)字運(yùn)算的實(shí)例代碼,有需要的朋友可以參考一下2013-10-10C# 如何實(shí)現(xiàn)一個(gè)基于值相等性比較的字典
這篇文章主要介紹了C# 如何實(shí)現(xiàn)一個(gè)基于值相等性比較的字典,幫助大家更好的理解和使用c#,感興趣的朋友可以了解下2021-02-02C#實(shí)現(xiàn)進(jìn)制轉(zhuǎn)換
這篇文章介紹了C#實(shí)現(xiàn)進(jìn)制轉(zhuǎn)換的方法,對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來(lái)一起學(xué)習(xí)學(xué)習(xí)吧2022-05-05