Хорошее решение ... Я должен обдумать это. +1 за этот хороший хак.

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

class Foo {public void Observer (регистр System.Action, unregister System.Action) {register (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)

Решение Вопроса

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

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

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

 Pierre Arnaud21 янв. 2011 г., 10:09
Если такие люди, как Эрик Мейер, не могли придумать более чистых решений, я подозреваю, что на самом деле другого способа сделать это нет. Это печально ... Спасибо за быстрый ответ, Джон.

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

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

public System.EventHandler LengthChanged; 

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

Foo foo = ...;
Dimension dim = ...;
foo.Observer (dim.LengthChanged); 
 Pierre Arnaud22 янв. 2011 г., 22:20
Хорошее решение ... Я должен обдумать это. +1 за этот хороший хак.
 Harvey Kwok21 янв. 2011 г., 18:17
@Pierre Я вижу .. в этом случае я бы объявил класс-обертку делегата. Конструктор этого класса принимает делегата. Класс имеет виртуальный AddHandler () и виртуальный RemoveHandler (). Он также имеет метод Invoke () для вызова делегата. Чтобы это выглядело более элегантно, вы можете определить операторы + =, - =, + и -, вызывая ваши AddHandler и RemoveHandler. Замените событие LengthChanged вашего измерения этим классом-оберткой. В этом случае вам нужны сеттеры «добавить» и «удалить», просто переопределите методы AddHandler и RemoveHandler этого класса-оболочки. Просто мои 2 цента. Я сделал подобное.
 Pierre Arnaud21 янв. 2011 г., 10:07
Спасибо за ваше предложение. Нет, я не могу передать делегат вместо события; событие может реализоватьadd а такжеremove сеттеры и действительно должны быть определены как полноценный C #event.

Ваш ответ на вопрос