我发现当我使用lambdas作为被断言方法的参数时,Rhino Mocks的AssertWasCalled失败了。
TEST:
_mockDoer.AssertWasCalled(x => x.Print(y => Console.WriteLine("hi")));
测试中的系统内部代码:
_doer.Print(y => Console.WriteLine("hi")));
这让我认为lambdas实际上是委托类型的构造函数。
当我认为lambdas是委托类型的构造函数时,我是否遗漏了任何重要内容?
答案 0 :(得分:9)
嗯,在“构造函数”这个词的任何正常用法中,它们并不是真正的“构造函数”。
它们是可以转换为委托类型或表达式树类型的表达式 - 后者在进程外LINQ时是必不可少的。
如果你真的在问是否期望使用两个“等效”lambda表达式可以创建不相等的委托实例:是的,它是。 IIRC,C#语言规范甚至提到了这种情况。
但是,多次使用相同的lambda表达式不会始终创建不同的实例:
using System;
class Test
{
static void Main(string[] args)
{
Action[] actions = new Action[2];
for (int i = 0; i < 2; i++)
{
actions[i] = () => Console.WriteLine("Hello");
}
Console.WriteLine(actions[0] == actions[1]);
}
}
在我的方框中,实际打印True
- actions[0]
和actions[1]
具有完全相同的值 - 它们引用相同的实例。的确,我们可以走得更远:
using System;
class Test
{
static void Main(string[] args)
{
object x = CreateAction();
object y = CreateAction();
Console.WriteLine(x == y);
}
static Action CreateAction()
{
return () => Console.WriteLine("Hello");
}
}
再次打印True
。这是不保证,但这里编译器实际上创建了一个静态字段来在第一次需要时缓存委托 - 因为它不捕获任何变量等。
基本上这是一个编译器实现细节,你不依赖它。
答案 1 :(得分:6)
只是为了扩展Jon的(优秀的,一如既往)答案:在当前的C#实现中,如果“相同的”lambda出现在两个不同的源代码位置那么这两个lambdas永远不会实现为平等的代表。但是,我们保留在未来检测这种情况并统一它们的权利。
converse是否成立也是依赖于实现的。如果从特定源代码位置的lambda创建了两个委托,则委托可能会也可能不具有相等性。在某些情况下,委托不可能具有相等性(例如,因为它们在局部变量的不同实例上是封闭的)。在 可能使它们具有相等性的情况下,大部分时间它们,但在某些情况下我们可以执行此优化而不是,只是因为编译器还不够复杂。