Замена кода котельной плиты - есть ли что-то плохое в этом коде? - PullRequest
18 голосов
/ 11 октября 2008

Я недавно создал эти два (не связанных) метода для замены большого количества кода на табличке в моем приложении winforms. Насколько я могу судить, они работают нормально, но мне нужны некоторые заверения / советы о том, есть ли какие-то проблемы, которые я мог бы пропустить.

(из памяти)

static class SafeInvoker
{
    //Utility to avoid boiler-plate InvokeRequired code
    //Usage: SafeInvoker.Invoke(myCtrl, () => myCtrl.Enabled = false);
    public static void Invoke(Control ctrl, Action cmd)
    {
        if (ctrl.InvokeRequired)
            ctrl.BeginInvoke(new MethodInvoker(cmd));
        else
            cmd();
    }

    //Replaces OnMyEventRaised boiler-plate code
    //Usage: SafeInvoker.RaiseEvent(this, MyEventRaised)
    public static void RaiseEvent(object sender, EventHandler evnt)
    {
        var handler = evnt;
        if (handler != null)
            handler(sender, EventArgs.Empty);
    }
}

РЕДАКТИРОВАТЬ: см. Связанный вопрос здесь

UPDATE

После проблем с тупиком (связанных с этим вопросом ) я переключился с Invoke на BeginInvoke (см. Объяснение здесь ).

Другое обновление

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

event EventHandler MyEventRaised = delegate {};

Ответы [ 3 ]

15 голосов
/ 11 октября 2008

Это хороший материал. Сделайте их методами расширения, хотя бы для того, чтобы немного очистить ваш код. Например:

//Replaces OnMyEventRaised boiler-plate code
//Usage: SafeInvoker.RaiseEvent(this, MyEventRaised)
public static void Raise(this EventHandler eventToRaise, object sender)
{
            EventHandler eventHandler = eventToRaise;

            if (eventHandler != null)
                eventHandler(sender, EventArgs.Empty);
}

Теперь о ваших событиях вы можете позвонить: myEvent.Raise (this);

3 голосов
/ 13 января 2010

Из-за того, что Бенджол не знает, почему он помещает Действие в MethodInvoker, и брокер, намеревавшийся использовать его в качестве функции расширения, вот код очистки:

static class SafeInvoker
{
    //Utility to avoid boiler-plate InvokeRequired code
    //Usage: myCtrl.SafeInvoke(() => myCtrl.Enabled = false);
    public static void SafeInvoke(this Control ctrl, Action cmd)
    {
        if (ctrl.InvokeRequired)
            ctrl.BeginInvoke(cmd);
        else
            cmd();
    }

    //Replaces OnMyEventRaised boiler-plate code
    //Usage: this.RaiseEvent(myEventRaised);
    public static void RaiseEvent(this object sender, EventHandler evnt)
    {
        if (evnt != null)
            evnt(sender, EventArgs.Empty);
    }
}

Просто последнее замечание: MethodInvoker и Action - это просто делегаты, имеющие одинаковую структуру. Из-за этого случая оба заменяются друг на друга. Корень этого именного столкновения происходит от наследия. В начале (.Net 2.0) было только MethodInvoker и Action(T). Но из-за того, что каждый, кто использовал Action(T), желает иметь Action и считает очень неестественным принимать MethodInvoker. Таким образом, в .Net 3.5 были добавлены Action, Action(T1, T2, T3, T4) и все делегаты Func, но MethodInvoker больше нельзя было удалить без внесения каких-либо критических изменений.

Дополнительно:

Если вы можете использовать .Net 3.5, приведенный выше код подходит, но если вы прикреплены к .Net 2.0, вы можете использовать его как обычную функцию, как и раньше, и заменить Action на MethodInvoker.

0 голосов
/ 11 октября 2008

Подобные паттерны сработали у меня без проблем. Я не уверен, почему вы добавляете Action в MethodInvoker.

...