Есть ли способ сделать эквивалент передачи «события» по ссылке? - PullRequest
2 голосов
/ 17 августа 2011

Я помещаю «событие» в кавычки, потому что я понимаю, что это немного синтаксического сахара, а не истинного типа.

У меня есть некоторые события, которые просто связаны с соответствующими событиями в другом классе.Поэтому, когда событие вызывается, отрывок выглядит как

Raiser -> Proxy -> Subscriber

Так что в классе Proxy у меня есть общий шаблон, подобный этому:

Raiser.SomeEvent += 
    (_, args) =>
    {
        if (this.SomeEvent != null)
            this.SomeEvent(this, args);
    };

Чтобы привести в порядок мой код, я хотел переместить это в другой метод, который возвращает новый делегат, который оборачивает указанный выше код вызова события:

public static EventHandler GetHandlerDelegate(EventHandler handler, Object sender)
{
    return
        (_, args) =>
        {                
            if (handler != null)
                handler(sender, args);
        };
    }      

А затем в Proxy я могу просто сделать:

Raiser.SomeEvent += GetHandlerDelegate(this.SomeEvent, this);

Что гораздо аккуратнее.

Что ж, это нормально, если подписчик не решает подписаться на Proxy.SomeEvent после вышеуказанного вызова.К сожалению, я не передаю «событие» по ссылке, как я надеялся;Теперь я понимаю, что я просто передаю список вызовов, поэтому, когда происходит OtherClass.SomeEvent и этот анонимный метод вызывается и вызывает «событие» (делегат), которое ему было дано, только те делегаты, которые были добавлены к этому событию в то время, когда я вызывал GetHandlerDelegate (), будет вызываться .Хотя этого на самом деле достаточно для моей текущей ситуации, на самом деле это неприемлемо для такого кодирования.

Я прочитал некоторые другие вопросы SO и понял, что есть что-то под названием Reactive Extensions, которое может помочь, но на этомраз я ищу более простое решение, если оно есть.(Если нет, я просто не буду этого делать.)

Есть ли другой способ выполнить то, что я пытаюсь сделать, без указанного недостатка?


Если этот вопроснеясно, см. мой ответ , который, надеюсь, поможет прояснить его.

Ответы [ 2 ]

3 голосов
/ 17 августа 2011

РЕДАКТИРОВАТЬ: Хорошо, я думаю, теперь я понял.Это на самом деле довольно просто.Вы должны быть в состоянии написать прокси, чтобы просто иметь событие, а затем заставить самого прокси подписаться на событие Райзера, например так (только для EventHandler - я вернусь к этому позже):

Proxy proxy = new Proxy();
raiser.SomeEvent += Proxy.Handler;

// Then in the subscriber...
proxy.ProxiedEvent += (whatever)

// And the proxy class...
public class Proxy
{
    public event EventHandler ProxiedEvent;

    public void Handler(object sender, EventArgs e)
    {
        EventHandler proxied = ProxiedEvent;
        if (proxied != null)
        {
            // Or pass on the original sender if you want to
            proxied(this, e);
        }
    }
}

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

Это то, о чем вы думали, или это, по крайней мере, помогает вам думать о вещах по-другому?

0 голосов
/ 17 августа 2011

Поскольку моя первоначальная цель:

Raiser.SomeEvent += GetHandlerDelegate(this.SomeEvent, this); 

невозможна, я пошел на компромисс и придумаю следующее:

Raiser.SomeEvent += (_, args) => RaiseEvent(this.SomeEvent, this, args); 

Принимая во внимание, что GetHandlerDelegate() вернет делегата, которыйвызывает событие, RaiseEvent() просто (как вы уже догадались) вызывает событие.

public static void RaiseEvent(EventHandler _event, Object sender, EventArgs args)
{
    if (_event != null)
        _event(sender, args);
}

И для поддержки событий с помощью пользовательских EventArgs:

public static void RaiseEvent<TArgs>(EventHandler<TArgs> _event, Object sender, TArgs args)
    where TArgs : EventArgs
{
    if (_event != null)
        _event(sender, args);
}

Я поместил эти методы встатический вспомогательный класс, поэтому фактический вызов немного уродливее;Вот пример:

ViewControl.OpenFilesetClick += (_, args) => EventHelper.Raise(OpenFilesetClick, this, args); 

(я также переименовал метод в Raise () и удалил необязательный this из передаваемого имени события).

Но я не совсембудучи убежденным, стоит ли это делать, учитывая, что альтернативу, возможно, легче читать:

ViewControl.OpenFilesetClick += (_, args) => 
{
    if (OpenFilesetClick != null)
        OpenFilesetClick(this, args);
};

В любом случае, это был интересный способ узнать больше о том, как работают события и делегаты (или как они не работают).

...