Как ссылаться на событие в C # - PullRequest
7 голосов
/ 21 января 2011

У меня есть следующий класс, который имеет одно публичное событие с именем 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. Я придумал два сценария, ни один из которых действительно не удовлетворяет:

  1. Определите интерфейс ILengthChanged с событием LengthChanged, затем убедитесь, что Dimension реализует ILengthChanged. Затем я должен предоставить одну реализацию метода Observer для каждого интерфейса, который я определяю. Это никоим образом не достаточно общий. Я действительно хотел бы иметь возможность просто передать ссылку на событие System.EventHandler.

  2. Используйте System.Action<System.EventHandler> обратные вызовы для регистрации и отмены регистрации обработчика событий в методе Observer, вот так:

    класс Foo { public void Observer (системный регистр действий, System.Action отменить регистрацию) { зарегистрироваться (this.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 могла бы каким-то образом добиться цели, но это не привело бы к проверке типов во время компиляции: я не хочу, чтобы пользователи Observer передавали ссылки на события, которые не удовлетворяют System.EventHandler подпись события.

Ответы [ 2 ]

10 голосов
/ 21 января 2011

К сожалению, на самом деле нет способа сделать это. События не являются первоклассными гражданами в .NET в целом - хотя F # пытается продвигать их там.

Либо передайте делегат подписки / отписки, либо используйте строку, указывающую название события. (Последний часто короче, но явно менее безопасен во время компиляции.)

Вот те подходы, которые Реактивные расширения используют - если бы был более чистый способ сделать это, я уверен, что они использовали бы это: (

2 голосов
/ 21 января 2011

Событие не должно передаваться в другой метод. Однако вы можете передать делегат в другой метод. Возможно, то, что вы ищете, это просто публичный делегат вместо события.

Если вы измените свое событие на

public System.EventHandler LengthChanged; 

Вы можете просто передать LengthChanged Observer следующим образом

Foo foo = ...;
Dimension dim = ...;
foo.Observer (dim.LengthChanged); 
...