将此委托转换为匿名方法或lambda

我是所有匿名function的新手,需要一些帮助。 我得到以下工作:

public void FakeSaveWithMessage(Transaction t) { t.Message = "I drink goats blood"; } public delegate void FakeSave(Transaction t); public void SampleTestFunction() { Expect.Call(delegate { _dao.Save(t); }).Do(new FakeSave(FakeSaveWithMessage)); } 

但这完全是丑陋的,我想让Do的内部成为匿名方法,如果可能的话,甚至是lambda。 我试过了:

 Expect.Call(delegate { _dao.Save(t); }).Do(delegate(Transaction t2) { t2.Message = "I drink goats blood"; }); 

 Expect.Call(delegate { _dao.Save(t); }).Do(delegate { t.Message = "I drink goats blood"; }); 

但这些给了我

无法将匿名方法转换为类型’System.Delegate’,因为它不是委托类型**编译错误。

我究竟做错了什么?


由于马克·英格拉姆发布的内容,似乎是最好的答案,尽管没有人明确说过,但这样做是:

 public delegate void FakeSave(Transaction t); Expect.Call(delegate { _dao.Save(t); }).Do( new FakeSave(delegate(Transaction t2) { t.Message = expected_msg; })); 

这是一个众所周知的错误消息。 请查看以下链接以获取更详细的讨论。

http://staceyw1.wordpress.com/2007/12/22/they-are-anonymous-methods-not-anonymous-delegates/

基本上你只需要在你的匿名委托(你的lambda表达式)前面放一个演员表。

如果链接发生故障,这里有一个post的副本:

它们是匿名方法,而不是匿名代理。
由staceyw1发布于2007年12月22日

这不仅仅是一个话题,因为我们想要变得困难。 它可以帮助我们推断出究竟发生了什么。 要明确的是,没有匿名代表这样的东西。 它们不存在(尚未存在)。 他们是“匿名方法” – 时期。 重要的是我们如何看待它们以及我们如何谈论它们。 让我们看一下匿名方法语句“delegate(){…}”。 这实际上是两种不同的操作,当我们这样想时,我们永远不会再混淆。 编译器所做的第一件事是使用推断的委托签名作为方法签名,在封面下创建匿名方法。 说该方法是“未命名”是不正确的,因为它确实有一个名称,编译器会分配它。 它只是隐藏在普通视图之外。 接下来要做的是创建一个包含方法所需类型的委托对象。 这称为委托推理,可能是这种混淆的根源。 为此,编译器必须能够找出(即推断)它将创建的委托类型。 它必须是已知的具体类型。 让我们写一些代码来了解原因。

 private void MyMethod() { } 

不编译:

 1) Delegate d = delegate() { }; // Cannot convert anonymous method to type 'System.Delegate' because it is not a delegate type 2) Delegate d2 = MyMethod; // Cannot convert method group 'MyMethod' to non-delegate type 'System.Delegate' 3) Delegate d3 = (WaitCallback)MyMethod; // No overload for 'MyMethod' matches delegate 'System.Threading.WaitCallback' 

第1行无法编译,因为编译器无法推断任何委托类型。 它可以清楚地看到我们想要的签名,但编译器没有具体的委托类型。 它可以为我们创建一个匿名类型的委托,但它不会那样工作。 由于类似的原因,第2行无法编译。 即使编译器知道方法签名,我们也没有给它一个委托类型,它不只是选择一个可能会起作用的(不是可能产生的副作用)。 第3行不起作用,因为我们故意将方法签名与具有不同签名的委托(如WaitCallback take和object)不匹配。

编译:

 4) Delegate d4 = (MethodInvoker)MyMethod; // Works because we cast to a delegate type of the same signature. 5) Delegate d5 = (Action)delegate { }; // Works for same reason as d4. 6) Action d6 = MyMethod; // Delegate inference at work here. New Action delegate is created and assigned. 

相比之下,这些工作。 第1行是有效的,因为我们告诉编译器要使用哪个委托类型并且它们匹配,所以它可以工作。 第5行也是出于同样的原因。 注意我们使用了没有parens的特殊forms的“委托”。 编译器从强制转换中推断出方法签名,并使用与推断的委托类型相同的签名创建匿名方法。 第6行有效,因为MyMethod()和Action使用相同的签名。

我希望这有帮助。

另见: http : //msdn.microsoft.com/msdnmag/issues/04/05/C20/

马克说的是什么。

问题是Do需要一个Delegate参数。 编译器无法将匿名方法转换为Delegate,只能转换为“委托类型”,即从Delegate派生的具体类型。

如果Do函数已经使Action <>,Action <,> …等重载,则不需要强制转换。

问题不在于您的委托定义,而是Do()方法的参数是System.Delegate类型,并且编译器生成的委托类型(FakeSave)不会隐式转换为System.Delegate。

尝试在匿名代表面前添加演员:

 Expect.Call(delegate { _dao.Save(t); }).Do((Delegate)delegate { t.Message = "I drink goats blood"; }); 

尝试以下方法:

 Expect.Call(delegate { _dao.Save(t); }).Do(new EventHandler(delegate(Transaction t2) { t2.CheckInInfo.CheckInMessage = "I drink goats blood"; })); 

请注意代理周围添加的EventHandler。

编辑:可能不起作用,因为EventHandler和委托的函数签名不一样…您添加到问题底部的解决方案可能是唯一的方法。

或者,您可以创建一个通用委托类型:

 public delegate void UnitTestingDelegate(T thing); 

因此委托不是特定于交易的。