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

时间:2008-09-12 16:58:33

标签: c# .net-3.5 delegates lambda anonymous-methods

我是所有匿名功能的新手,需要一些帮助。我已经完成了以下工作:

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; }));

4 个答案:

答案 0 :(得分:27)

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

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

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

如果链接发生故障,这里有帖子的副本:

  

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

     

这不仅仅是一个话题,因为   我们想要变得困难。它帮助我们   关于到底发生了什么的原因。   要清楚,没有这样的事情   作为匿名代表。他们没有   存在(尚未)。他们是“匿名的   方法“ - 期间。重要的是如何   我们想到了它们以及我们如何谈论它们   他们。让我们来看看   匿名方法语句“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   采取和反对)。

     

编译:

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的“代表”形式。   编译器推断出该方法   来自演员的签名和创作   匿名方法与此相同   签名作为推断的委托   类型。第6行的作用是因为   MyMethod()和Action使用相同的   签名。

     

我希望这会有所帮助。

     

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

答案 1 :(得分:3)

Mark说的话。

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

如果该Do函数已执行Action<>,则Action<,> ......等重载,你不需要演员。

答案 2 :(得分:1)

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

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

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

答案 3 :(得分:0)

尝试类似:

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>(T thing);

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