方法组的行为与la​​mbda不同?

时间:2016-05-16 14:21:31

标签: c# moq

我正在使用Moq来模拟某个界面。这是:

var titleGenerator = new Mock<ITitleGenerator>();
titleGenerator.Setup(t => t.GenerateTitle()).Returns(Guid.NewGuid().ToString);

Console.WriteLine(titleGenerator.Object.GenerateTitle());
Console.WriteLine(titleGenerator.Object.GenerateTitle());

两次打印相同的值。但如果我用这个替换第二行:

titleGenerator.Setup(t => t.GenerateTitle()).Returns(() => Guid.NewGuid().ToString());

它会在每次调用时返回唯一值。

我一直以为方法组只是lambda表达式的快捷方式。有什么区别吗?我试着在文档中搜索任何解释。有人可以开导我吗?

看起来方法组只评估表达式并以某种方式缓存它?或者它与Moq有什么关系?

3 个答案:

答案 0 :(得分:9)

在第一个示例中,您传递了单个ToString的{​​{1}}函数,然后在每次调用时调用它。它等同于:

Guid

在第二个示例中,您传递的函数首先创建一个新的Guid guid = Guid.NewGuid(); titleGenerator.Setup(t => t.GenerateTitle()).Returns(guid.ToString) ,然后在其上调用Guid

答案 1 :(得分:0)

区别在于输入。在第一种情况下,“方法组”实际上是Guid.ToString的委托。但由于它需要实例作为“输入”,因此实例是委托表达式的一部分,因此每次都使用相同的“输入”。

这相当于:

var titleGenerator = new Mock<ITitleGenerator>();
Guid g = Guid.NewGuid();
titleGenerator.Setup(t => t.GenerateTitle()).Returns(g.ToString);

在第二种情况下,委托没有输入Guid实例在委托中计算,因此每次都会使用新的Guid

答案 2 :(得分:0)

对于可能更容易理解的等效示例,代码:

var id = 1;
Func<string> f = id.ToString;
id = 2;
Console.WriteLine(f()); // 1

将写"1",而:

var id = 1;
Func<string> f = () => id.ToString();
id = 2;
Console.WriteLine(f()); // 2

将写"2"

第一种情况中,创建了委托(Func<>实例)f,其值1Target,方法信息string int.ToString()Method。稍后重新分配到id不会影响f

第二种情况中,事情会更加间接。编译器将生成一个与=>箭头对应的新方法。本地变量id 已捕获已关闭(位于lambda的闭包中)。这意味着,在幕后,id实际上被提升为某个地方的field(编译器的选择)。当您的方法提到id时,它确实会访问该字段。并且与=>箭头对应的编译器生成的方法也读取该字段。现在创建Func<>,其Method属性是此编译器生成的方法。因此,结果将是"2"。这是C#中匿名函数的闭包语义。

你原来的Moq示例是一样的。有问题的Returns重载需要参数Func<TResult> valueFunction,其中TResultstring。在我更简单的示例中,valueFunction就是我所谓的f