2

我发现自己做了很多以下事情,我不知道是否有任何副作用,但在 WinForms C# 应用程序中考虑以下内容。(请原谅我在输入代码时出现的任何错误,而不是复制粘贴任何内容)

int a = 1;
int b = 2;
int c = 3;
this.Invoke((MethodInvoker)delegate()
{
    int lol = a + b + c;
});

这有什么问题吗?还是我应该走很长的路>_<

int a = 1;
int b = 2;
int c = 3;
TrippleIntDelegate ffs = new TrippleIntDelegate(delegate(int a_, int b_, int c_)
{
   int lol = a_ + b_ + c_;
});

this.Invoke(ffs);

不同之处在于参数是传入而不是使用局部变量,这是一些非常甜蜜的 .net 魔术。我想我曾经看过反射器,它创建了一个全新的类来保存这些变量。

那么这有关系吗?我可以偷懒吗?

编辑:注意,显然不关心返回值。否则我将不得不使用我自己的类型化委托,尽管我仍然可以使用局部变量而不传递它!

4

4 回答 4

3

你使用它的方式,它并没有真正的不同。但是,在第一种情况下,您的匿名方法正在捕获变量,如果您不知道自己在做什么,这可能会产生很大的副作用。例如 :

// No capture :
int a = 1;
Action<int> action = delegate(int a)
{
    a = 42; // method parameter a
});
action(a);
Console.WriteLine(a); // 1

// Capture of local variable a :
int a = 1;
Action action = delegate()
{
    a = 42; // captured local variable a
};
action();
Console.WriteLine(a); // 42
于 2010-02-25T02:26:57.073 回答
1

只要您了解您正在延迟执行,传递局部变量就没有错。如果你这样写:

int a = 1;
int b = 2;
int c = 3;
Action action = () => Console.WriteLine(a + b + c);
c = 10;
action();  // Or Invoke(action), etc.

输出将是 13,而不是 6。我想这将与 Thomas 所说的对应;如果您在委托中读取本地变量,它将使用实际执行操作时变量所持有的任何值,而不是在声明时。如果变量包含引用类型并且您异步调用委托,这可能会产生一些有趣的结果。

除此之外,还有很多充分的理由将局部变量传递给委托;除其他外,它还可用于简化线程代码。只要你不马虎,这样做是完全可以的。

于 2010-02-25T02:52:46.857 回答
1

好吧,所有其他答案似乎都忽略了多线程上下文以及在这种情况下出现的问题。如果您确实在 WinForms 中使用它,那么您的第一个示例可能会引发异常。根据您尝试从委托中引用的实际数据,实际调用代码的线程可能有权也可能无权访问您关闭的数据。

另一方面,您的第二个示例实际上是通过参数传递数据。这允许 Invoke 方法跨线程边界正确编组数据并避免那些讨厌的线程问题。如果您从后台工作人员调用 Invoke,那么您应该使用类似于第二个示例的内容(尽管我会选择使用 Action<T, ...> 和 Func<T, ...> 代表可能而不是创造新的)。

于 2010-02-25T02:58:22.133 回答
0

从风格的角度来看,我会选择参数传递变体。它表达了更容易传递 args 而不是任何类型的 take 环境的意图(并且也更容易测试)。我的意思是,你可以这样做:

public void Int32 Add()
{
    return this.Number1 + this.Number2
}

但它既不可测试也不清晰。带参数的 sig 对其他人来说更清楚该方法正在做什么......它添加了两个数字:而不是任意一组数字或其他任何数字。

我经常使用像集合这样的参数来执行此操作,这些参数无论如何都通过 ref 使用,并且不需要明确地“返回”:

public List<string> AddNames(List<String> names)
{
    names.Add("kevin");
    return names;
}

即使名称集合由 ref 传递,因此不需要显式返回,但对我来说更清楚的是,该方法获取列表并将其添加到其中,然后将其返回。在这种情况下,以这种方式编写 sig没有技术上的理由,但对我来说,就清晰度和可维护性而言,这是一个很好的理由。

于 2010-02-25T02:34:36.613 回答