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


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


