logo search
CSharp_Prog_Guide

Пример44

В следующем примере показано, как действовать в не очень распространенном случае, когда класс наследует от двух или более интерфейсов и каждый интерфейс имеет событие с тем же именем. В такой ситуации, по меньшей мере, для одного из событий следует предоставить явную реализацию интерфейса. При написании явной реализации интерфейса для события необходимо также написать методы доступа к событию add и remove. Как правило, они обеспечиваются компилятором, в этом случае компилятор не сможет предоставить их.

При помощи собственных методов доступа можно определить, будут ли два события представлены одним событием в классе или разными событиями. Например, если события должны инициироваться в разное время в зависимости от требований интерфейса, то каждое событие можно связать с отдельной реализацией в классе. В следующем примере подписчики определяют, какое событие OnDraw они получат путем приведения ссылки на форму к IShape или IDrawingObject.

-----

// 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;

// Explicit interface implementation required.

// Associate IDrawingObject's event with

// PreDrawEvent

event EventHandler IDrawingObject.OnDraw

{

add

{

if (null!=PreDrawEvent) lock (PreDrawEvent)

{

PreDrawEvent += value;

} else PreDrawEvent += value;

}

remove

{

lock (PreDrawEvent)

{

PreDrawEvent -= value;

}

}

}

// Explicit interface implementation required.

// Associate IShape's event with

// PostDrawEvent

event EventHandler IShape.OnDraw

{

add

{

if (null != PostDrawEvent) lock (PostDrawEvent)

{

PostDrawEvent += value;

} else PostDrawEvent += value;

}

remove

{

lock (PostDrawEvent)

{

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();

Console.WriteLine("Press Enter to close this window.");

Console.ReadLine();

}

}

}

Sub1 receives the IDrawingObject event.

Drawing a shape.

Sub2 receives the IShape event.

-----

How to: Use a Dictionary to Store Event Instances

One use for accessor-declarations is to expose many events without allocating a field for each event, but instead using a Dictionary to store the event instances. This is only useful if you have many events, but you expect most of the events will not be implemented.

Example

public delegate void EventHandler1(int i);

public delegate void EventHandler2(string s);

public class PropertyEventsSample

{

private System.Collections.Generic.Dictionary<string, System.Delegate> eventTable;

public PropertyEventsSample()

{

eventTable = new System.Collections.Generic.Dictionary<string, System.Delegate>();

eventTable.Add("Event1", null);

eventTable.Add("Event2", null);

}

public event EventHandler1 Event1

{

add

{

lock (eventTable)

{

eventTable["Event1"] = (EventHandler1)eventTable["Event1"] + value;

}

}

remove

{

lock (eventTable)

{

eventTable["Event1"] = (EventHandler1)eventTable["Event1"] - value;

}

}

}

public event EventHandler2 Event2

{

add

{

lock (eventTable)

{

eventTable["Event2"] = (EventHandler2)eventTable["Event2"] + value;

}

}

remove

{

lock (eventTable)

{

eventTable["Event2"] = (EventHandler2)eventTable["Event2"] - value;

}

}

}