在Java中我们可以做类似
的事情final string str = "I am a string";
Thread thread = new Thread(...{
string str2 = "bla bla bla " + str;
});
我不完全理解如何做到这一点,但重点是我需要声明str为最终在我的线程中访问它所以没有可变的腐败。
但是现在我如何在C#中做到这一点
string str = "I am a string";
Task.Run(() => {
string str2 = "bla bla " + str;
});
它确实有效,但我不确定这是否正确。我正在使用Visual Studio for Xamarin。
答案 0 :(得分:9)
让我们退后一步。
在C#中创建lambda时,将外部变量捕获为变量:
int x = 123;
Action change = () => { Console.WriteLine(x); x = 345; };
Console.WriteLine(x); // 123
change(); // 123
Console.WriteLine(x); // 345
change(); // 345
x = 789;
change(); // 789
Console.WriteLine(x); // 345
只有一个变量x ,并且lambda的共享和方法的激活。
这非常有用,但有些情况下可能会让超级混乱:
List<Action> actions = new List<Action>();
for(int x = 0; x < 10; ++x)
{
actions.Add(() => { Console.WriteLine(x); });
}
actions[0](); // 10, surprise!
只有一个变量x,所有lambdas都共享它。
有些人想要第一个行为 - lambdas共享变量 - 但编写第二种程序的人想要第二种行为。他们希望lambdas捕获变量的当前值,而不是变量本身。
C#只需选择第一个选项即可解决此问题。 Java通过使第一个场景非法解决了这个问题。如果你只能捕获永远不会改变的变量那么你就没有将变量捕获为变量的好处或问题。
我个人更喜欢C#选择,尽管它有缺点。但两者都是合理的,合理的和有原则的。不同的语言设计师做出不同的选择。
该功能与线程安全本身无关。 (虽然它有线程安全方面;在C#中通过lambdas在线程之间共享的变量是 not volatile 。)相反,它是关于lambda捕获变量如何工作的设计决策。
答案 1 :(得分:1)
我不完全理解如何做到这一点,但重点是我需要声明str为最终在我的线程中访问它所以没有 可变腐败。
不,重点在于线程声明包含Java闭包,这就是Java闭包的工作方式,即它们只能使用不可变(final
)对象创建。 C#中不存在该问题。
答案 2 :(得分:0)