Как ссылка на событие в C#
у меня есть следующий класс, который имеет одно публичное мероприятие под названием LengthChanged
:
class Dimension
{
public int Length
{
get
{
return this.length;
}
set
{
if (this.length != value)
{
this.length = value;
this.OnLengthChanged ();
}
}
protected virtual void OnLengthChanged()
{
var handler = this.LengthChanged;
if (handler != null)
{
handler (this, System.EventArgs.Empty);
}
}
public event System.EventHandler LengthChanged;
private int length;
}
я хотел бы иметь возможность зарегистрировать / отменить регистрацию обработчиков для этого события в методе Observer
, который ничего не знает о Dimension
класса. Я придумал два сценария, ни один из которых не очень сытно:
определить интерфейс
ILengthChanged
СLengthChanged
событие, то убедитесь, чтоDimension
осуществляетILengthChanged
. Тогда я должен ... обеспечить одну реализациюObserver
метод для каждого интерфейса, который я определяю. Этого никак не достаточно общего. Я действительно хотел бы иметь возможность просто передать ссылку наSystem.EventHandler
событие.-
использовать
System.Action<System.EventHandler>
обратные вызовы для регистрации и отмены регистрации обработчиков событий вObserver
метод, как это:класс Foo { public void Observer (System.Регистр действий, Система.Отменить действие ) { реестр (этот.MyEventHandler);
// keep track of the unregister callback, so that we can unregister // our event handler later on, if needed... } private void MyEventHandler(object sender, System.EventArgs e) { ... }
}
который затем будет вызываться следующим образом:
Foo foo = ...;
Dimension dim = ...;
foo.Observer (x => dim.LengthChanged += x, x => dim.LengthChanged -= x);
и который, когда будет выполнен, действительно закончится проводкой LengthChanged
событие с внутренним обработчиком событий MyEventHandler
. Но это не очень элегантно. Я хотел бы иметь возможность написать это вместо этого:
Foo foo = ...;
Dimension dim = ...;
foo.Observer (dim.LengthChanged);
но я понятия не имею, как этого можно достичь. Может быть, я упускаю что-то очень очевидное? Я думаю, что некоторые dynamic
magic может каким-то образом сделать трюк, но это не будет принудительно проверять тип времени компиляции: я не хочу пользователей Observer
передать ссылки на события, которые не удовлетворяют System.EventHandler
подпись событие.
2 ответов
к сожалению, на самом деле нет способа сделать это. События не являются гражданами первого класса в .NET в целом - хотя F# пытается продвигать их там.
либо передайте делегат subscribe/unsubscribe, либо используйте строку, указывающую имя события. (Последнее часто короче, но, очевидно, менее безопасно во время компиляции.)
те подходы, которые Реактивные Расширения принимает-если бы был более чистый способ сделать это, я уверен, что они будет использовать это : (
событие не должно передаваться в другой способ. Однако вы можете передать delegate в другой метод. Возможно, то, что вы ищете, - это просто простой публичный делегат вместо события.
Если вы измените свое событие для этого
public System.EventHandler LengthChanged;
Вы можете просто передать LengthChanged наблюдателю, как это
Foo foo = ...;
Dimension dim = ...;
foo.Observer (dim.LengthChanged);