Подтвердить что ты не робот

Анонимные делегаты в С#

Я не могу быть единственным, кто устал от определения и назначения делегата только за один вызов того, что требует делегата. Например, я хотел вызвать .Refresh() в форме из возможных других потоков, поэтому я написал этот код:

private void RefreshForm()
{
    if (InvokeRequired)
        Invoke(new InvokeDelegate(Refresh));
    else
        Refresh();
}

Я даже не уверен, что должен, я просто достаточно читал, чтобы испугаться, что он не сработает на более позднем этапе. InvokeDelegate фактически объявлен в другом файле, но действительно ли мне нужен целый делегат, посвященный именно этому? нет ли вообще общих делегатов?
Я имею в виду, например, класс Pen, но также и Pens.pen-of-choice, поэтому вам не нужно переделывать все это. Это не то же самое, но я надеюсь, вы понимаете, что я имею в виду.

4b9b3361

Ответ 1

Да. В .NET 3.5 вы можете использовать Func и Action делегаты. Делегаты Func возвращают значение, а делегаты Action возвращают void. Вот как выглядели бы имена типов:

System.Func<TReturn> // (no arg, with return value)
System.Func<T, TReturn> // (1 arg, with return value)
System.Func<T1, T2, TReturn> // (2 arg, with return value)
System.Func<T1, T2, T3, TReturn> // (3 arg, with return value)
System.Func<T1, T2, T3, T4, TReturn> // (4 arg, with return value)

System.Action // (no arg, no return value)
System.Action<T> // (1 arg, no return value)
System.Action<T1, T2> // (2 arg, no return value)
System.Action<T1, T2, T3> // (3 arg, no return value)
System.Action<T1, T2, T3, T4> // (4 arg, no return value)

Я не знаю, почему они остановились на 4 аргумента каждый, но мне всегда было достаточно.

Ответ 2

Там делегат Action вы можете использовать, например:

private void RefreshForm()
{
    if (InvokeRequired) Invoke(new Action(Refresh));
    else Refresh();
}

Или, с синтаксисом лямбда:

private void RefreshForm()
{
    if (InvokeRequired) Invoke((Action)(() => Refresh()));
    else Refresh();
}

Наконец, есть анонимный синтаксис делегата:

private void RefreshForm()
{
    if (InvokeRequired) Invoke((Action)(delegate { Refresh(); }));
    else Refresh();
}

Ответ 3

В этом конкретном случае вы можете (и должны) просто использовать MethodInvoker для этого... вот почему он существует.

if (InvokeRequired)
    Invoke(new MethodInvoker(Refresh));
else
    Refresh();

Если вы делали что-то еще, вы могли бы, как ответили другие, использовать Func < T,... > или Action < T,... > если они соответствуют вашему варианту использования.

Ответ 4

Краткая версия:

Invoke((MethodInvoker)delegate { Refresh(); });

Затем вы также можете сбросить проверку InvokeRequired; вы можете просто назвать это так, как есть. Работает также, если вам нужно передать параметры, поэтому нет необходимости в других делегатах, специфичных для параметра (работает так же хорошо с делегатом Action-less Action):

private void SetControlText(Control ctl, string text)
{
    Invoke((MethodInvoker)delegate { ctl.Text = text; });
}

Ответ 5

Мне действительно нужен весь делегат посвященный только для этого? не существует любые общие делегаты вообще?

Определение собственных делегатов может действительно облегчить отладку, хотя бы потому, что Intellisense может указать вам имена ваших параметров. Например, вы пишете делегат следующим образом:

public delegate int UpdateDelegate(int userID, string city, string, state, string zip);

Когда вы используете этот код,.NET сообщит вам имена параметров, имя делегата и т.д., так что в определении делегата есть много контекста, если вы точно не знаете, как что-то используется.

Однако, если вы не против жертвовать Intellisense, уже существует класс делегатов, определенных в пространстве имен System, которые могут использоваться как специальные делегаты:

Func<T>
Func<T, U>
Func<T, U, V>
Func<T, U, V, W>
Action, Action<T>
Action<T, U>
Action<T, U, V>
Action<T, U, V, W>

В .NET 2.0 существуют только Action и Action, но достаточно легко объявить вспомогательный класс с оставшимися делегатами, которые вам нужны для разных видов специальных функций.

Ответ 6

Да, есть общие делегаты. Action<T1, T2...> - это общий делегат, который принимает некоторые параметры и не возвращает значения, а Func<T1, T2...R> - это общий делегат, который принимает некоторые параметры и возвращает значение.