提问人:Charly 提问时间:1/27/2021 更新时间:1/29/2021 访问量:70
如果 在 lambda 之前和在 lambda 内部实例化对象,则 C# 闭包行为会发生变化?
C# closures behavior changes if a instantiate the object before versus inside the lambda?
问:
因此,我发现了一种奇怪的现象,即我的代码的行为会根据我在 lambda 函数中分配将要“关闭”的对象的位置而变化。
这是我所经历的一个简化的例子
Example01(){
var myCounterLocalInstance = new MyCounter();
Action<string> lambdaFunction = (args) => IncrementAndPrint(args, myCounterLocalInstance);
}
Example02(){
Action<string> lambdaFunction = (args) => IncrementAndPrint(args, new MyCounter());
}
IncrementAndPrint(string args, MyCounter counter){
Console.WriteLine(args + counter.GetValueAndCount());
}
class MyCounter
{
int _counter;
public int GetValueAndCount() => _counter++;
}
奇怪的是,在我的情况下,Example01 和 Example02 实际上并没有给出相同的结果。在 Example01 中,一切都按预期工作,控制台输出将是,如果 args == “cat”:
- 日志:“cat0”
- 日志:“cat1”
- 日志:“cat2”
这是预期行为,因为 MyCounter 是有状态的。 但是,Example02 将给出以下输出:
- 日志:“cat0”
- 日志:“cat0”
- 日志:“cat0”
每次调用该方法时,都会重置_counter成员变量...这就像 myCounter 是按值传递的,并且每次在 Example02 中使用时都会被重新实例化,而不是像第一个示例中那样被放入闭包对象中——就像预期的那样。
对此有什么解释吗?我猜这是已知行为而不是错误?关于关闭,一定有什么我不知道的事情。这让我非常头疼,因为我从没想过行为会根据我在哪里分配闭包的参数而改变。
谢谢!
答:
1赞
TheGeneral
1/27/2021
#1
你想多了。
在此方法中,您将创建一个 的实例,该实例在每次调用委托时递增。MyCounter
static void Example01(){
var myCounterLocalInstance = new MyCounter();
Action<string> lambdaFunction = (args) => IncrementAndPrint(args, myCounterLocalInstance);
lambdaFunction("cat");
lambdaFunction("cat");
lambdaFunction("cat");
lambdaFunction("cat");
}
在此方法中,每次调用委托时都会创建一个新实例,其计数将始终为 0!MyCounter
static void Example02(){
Action<string> lambdaFunction = (args) => IncrementAndPrint(args, new MyCounter());
lambdaFunction("cat");
lambdaFunction("cat");
lambdaFunction("cat");
lambdaFunction("cat");
}
如果你只是静态地调用,你会得到相同的结果:IncrementAndPrint
static void Example01(){
var myCounterLocalInstance = new MyCounter();
IncrementAndPrint("cat",myCounterLocalInstance);
IncrementAndPrint("cat",myCounterLocalInstance);
IncrementAndPrint("cat",myCounterLocalInstance);
IncrementAndPrint("cat",myCounterLocalInstance);
}
static void Example02(){
IncrementAndPrint("cat", new MyCounter());
IncrementAndPrint("cat", new MyCounter());
IncrementAndPrint("cat", new MyCounter());
IncrementAndPrint("cat", new MyCounter());
}
评论
lambdaFunction = (args) => IncrementAndPrint(args, new MyCounter());
lambdaFunction
Example01
Example02
IncrementAndPrint("cat", myCounterLocalInstance)
IncrementAndPrint("cat", new MyCounter());
new MyCounter()
在每次调用时被调用。它每次都会得到一个新的。