将两个参数传递给线程池上的新线程有时会很复杂,但看起来使用lambda表达式和匿名方法,我可以这样做:
public class TestClass
{
public void DoWork(string s1, string s2)
{
Console.WriteLine(s1);
Console.WriteLine(s2);
}
}
try
{
TestClass test = new TestClass();
string s1 = "Hello";
string s2 = "World";
ThreadPool.QueueUserWorkItem(
o => test.DoWork(s1, s2)
);
}
catch (Exception ex)
{
//exception logic
}
现在,我肯定简化了这个例子,但这些要点是关键:
这有什么问题吗?
另一种方法是创建一个实现具有3个成员的不可变类型的新类:test,s1和s2。这似乎只是额外的工作而没有任何好处。
答案 0 :(得分:16)
这没有错。编译器基本上是自动执行您所描述的替代方案。它创建了一个类来保存捕获的变量(test,s1和s2),并将委托实例传递给lambda,lambda将转换为匿名类的方法。换句话说,如果你继续使用替代方案,那么最终会得到与编译器为你生成的东西非常相似的东西。
答案 1 :(得分:4)
对于这个特例,这里没有任何错误。您传递到另一个线程的状态是完全包含的,并且所涉及的类型都没有任何线程关联问题。
答案 2 :(得分:2)
这是一种很好的方式。我没有看到使用lambdas的任何缺点。它简单而干净。
答案 3 :(得分:2)
你所看到的被称为封闭。作为chuckj states,编译器在编译时生成一个类,该类对应于在闭包之外访问的成员。
你唯一需要担心的是你是否有参考或参数。虽然字符串是不可变的,但对它们(或任何变量)的引用都不是。
答案 4 :(得分:2)
该模式的一个潜在问题是,非常很容易将其扩展为更通用但更不安全的东西(刮擦代码 - 不要指望它能够工作):
public static void QueueTwoParameterWorkItem<T1, T2>(T1 value1, T2 value2, workDelegate<T1,T2> work)
{
try
{
T1 param1 = value1;
T2 param2 = value2;
ThreadPool.QueueUserWorkItem(
(o) =>
{
work(param1, param2);
});
}
catch (Exception ex)
{
//exception logic
}
}