34

我不能是唯一一个厌倦了定义和命名委托的人,因为我只是对需要委托的东西的一次调用。例如,我想以可能来自其他线程的表单调用 .Refresh(),所以我编写了以下代码:

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

我什至不确定我必须这样做,我只是读了足够多的书,害怕它在以后的某个阶段不起作用。
InvokeDelegate 实际上是在另一个文件中声明的,但我真的需要一个专门为此而设计的委托吗?根本没有任何通用代表吗?
我的意思是,例如,有一个 Pen 类,但也有 Pens。选择笔,因此您不必重新制作整个东西。不一样,但我希望你明白我的意思。

4

6 回答 6

52

是的。在 .NET 3.5 中,您可以使用FuncAction委托。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 个 args 上,但这对我来说已经足够了。

于 2009-06-10T20:53:28.823 回答
26

您可以使用 Action 委托,如下所示:

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

或者,使用 lambda 语法:

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

最后是匿名委托语法:

private void RefreshForm()
{
    if (InvokeRequired) Invoke((Action)(delegate { Refresh(); }));
    else Refresh();
}
于 2009-06-10T20:50:51.980 回答
8

在这种特定情况下,您可以(并且应该)只使用MethodInvoker来执行此操作……这就是它存在的原因。

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

如果您正在做其他事情,正如其他人回答的那样,如果它们适合您的用例,请使用 Func<T,...> 或 Action<T,...> 。

于 2009-06-10T21:04:33.187 回答
5

简洁版本:

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

然后你也可以去掉 InvokeRequired 的勾选;你可以直接调用它。如果您需要传递参数,也可以使用,因此不需要其他特定于参数的委托(也可以与无参数的 Action 委托一起使用):

private void SetControlText(Control ctl, string text)
{
    Invoke((MethodInvoker)delegate { ctl.Text = text; });
}
于 2009-06-10T20:49:40.143 回答
2

我真的需要一个专门的代表吗?根本没有任何通用代表吗?

定义您自己的委托确实可以使调试更容易,因为 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 中ActionAction但它很容易声明一个助手类,其中包含这些杂项即席函数所需的剩余委托。

于 2009-06-10T20:59:22.667 回答
1

是的,有通用代表。 Action<T1, T2...>是一个接受一些参数但不返回值Func<T1, T2...R>的泛型委托,是一个接受一些参数并返回一个值的泛型委托。

于 2009-06-10T20:53:57.963 回答