結(jié)合.net框架在C#派生類中觸發(fā)基類事件及實(shí)現(xiàn)接口事件
在派生類中引發(fā)基類事件
以下簡單示例演示了在基類中聲明可從派生類引發(fā)的事件的標(biāo)準(zhǔn)方法。此模式廣泛應(yīng)用于 .NET Framework 類庫中的 Windows 窗體類。
在創(chuàng)建可用作其他類的基類的類時(shí),應(yīng)考慮如下事實(shí):事件是特殊類型的委托,只可以從聲明它們的類中調(diào)用。派生類無法直接調(diào)用基類中聲明的事件。盡管有時(shí)需要事件僅由基類引發(fā),但在大多數(shù)情形下,應(yīng)該允許派生類調(diào)用基類事件。為此,您可以在包含該事件的基類中創(chuàng)建一個(gè)受保護(hù)的調(diào)用方法。通過調(diào)用或重寫此調(diào)用方法,派生類便可以間接調(diào)用該事件。
注意:不要在基類中聲明虛擬事件,也不要在派生類中重寫這些事件。C# 編譯器無法正確處理這些事件,并且無法預(yù)知的該派生的事件的用戶是否真正訂閱了基類事件。
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)接口事件
接口可聲明事件。下面的示例演示如何在類中實(shí)現(xiàn)接口事件。實(shí)現(xiàn)接口事件的規(guī)則與實(shí)現(xiàn)任何接口方法或?qū)傩缘囊?guī)則基本相同。
在類中實(shí)現(xiàn)接口事件
在類中聲明事件,然后在適當(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); } } } }
下面的示例演示如何處理以下的不常見情況:您的類是從兩個(gè)以上的接口繼承的,每個(gè)接口都含有同名事件)。在這種情況下,您至少要為其中一個(gè)事件提供顯式接口實(shí)現(xiàn)。為事件編寫顯式接口實(shí)現(xiàn)時(shí),必須編寫 add 和 remove 事件訪問器。這兩個(gè)事件訪問器通常由編譯器提供,但在這種情況下編譯器不能提供。
您可以提供自己的訪問器,以便指定這兩個(gè)事件是由您的類中的同一事件表示,還是由不同事件表示。例如,根據(jù)接口規(guī)范,如果事件應(yīng)在不同時(shí)間引發(fā),則可以將每個(gè)事件與類中的一個(gè)單獨(dú)實(shí)現(xiàn)關(guān)聯(lián)。在下面的示例中,訂戶將形狀引用強(qiáng)制轉(zhuǎn)換為 IShape 或 IDrawingObject,從而確定自己將會接收哪個(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#中的泛型類與泛型接口
欄 目:C#教程
下一篇:C#中的delegate委托類型基本學(xué)習(xí)教程
本文標(biāo)題:結(jié)合.net框架在C#派生類中觸發(fā)基類事件及實(shí)現(xiàn)接口事件
本文地址:http://mengdiqiu.com.cn/a1/C_jiaocheng/6721.html
您可能感興趣的文章
- 01-10.net2.0+ Winform項(xiàng)目實(shí)現(xiàn)彈出容器層
- 01-10asp.net中XML如何做增刪改查操作
- 01-10C#使用ADO.Net部件來訪問Access數(shù)據(jù)庫的方法
- 01-10時(shí)間戳與時(shí)間相互轉(zhuǎn)換(php .net精確到毫秒)
- 01-10C#.NET實(shí)現(xiàn)網(wǎng)頁自動(dòng)登錄的方法
- 01-10C#裝箱和拆箱原理詳解
- 01-10實(shí)現(xiàn)ASP.NET無刷新下載并提示下載完成的開發(fā)思路
- 01-10C#.NET中如何批量插入大量數(shù)據(jù)到數(shù)據(jù)庫中
- 01-10C#.Net ArrayList的使用方法
- 01-10ASP.NET MVC命名空間時(shí)引起錯(cuò)誤的解決方法


閱讀排行
本欄相關(guān)
- 01-10C#通過反射獲取當(dāng)前工程中所有窗體并
- 01-10關(guān)于ASP網(wǎng)頁無法打開的解決方案
- 01-10WinForm限制窗體不能移到屏幕外的方法
- 01-10WinForm繪制圓角的方法
- 01-10C#實(shí)現(xiàn)txt定位指定行完整實(shí)例
- 01-10WinForm實(shí)現(xiàn)仿視頻 器左下角滾動(dòng)新
- 01-10C#停止線程的方法
- 01-10C#實(shí)現(xiàn)清空回收站的方法
- 01-10C#通過重寫Panel改變邊框顏色與寬度的
- 01-10C#實(shí)現(xiàn)讀取注冊表監(jiān)控當(dāng)前操作系統(tǒng)已
隨機(jī)閱讀
- 01-10使用C語言求解撲克牌的順子及n個(gè)骰子
- 01-10C#中split用法實(shí)例總結(jié)
- 08-05織夢dedecms什么時(shí)候用欄目交叉功能?
- 01-11Mac OSX 打開原生自帶讀寫NTFS功能(圖文
- 08-05dedecms(織夢)副欄目數(shù)量限制代碼修改
- 01-11ajax實(shí)現(xiàn)頁面的局部加載
- 01-10delphi制作wav文件的方法
- 08-05DEDE織夢data目錄下的sessions文件夾有什
- 01-10SublimeText編譯C開發(fā)環(huán)境設(shè)置
- 04-02jquery與jsp,用jquery