使用VS2013,在下面的示例中,在尝试将函数传递给worker的构造函数时会给出两个不同的错误,但是,具有相同原型的lambda函数是可以的。
我做错了什么,如何更改GetA
函数的定义以允许它被传递?
为了避免因误解类继承如何工作而引起的类似问题的混淆,我在这个例子中故意避免任何继承。
WorkerA
只能接受其中Func<A>
的构造函数。
WorkerAorB
更灵活,可以接受Func<A>
或Func<B>
。
WorkerAandB
是最有能力的,并且可以同时接受Func<A>
和Func<B>
(或者任何一个)。它最接近我的真实代码。
但是,当管理器中的代码尝试实例化工作程序时,WorkerA
按预期工作,但WorkerAorB
会出错:
错误CS0121:以下方法之间的呼叫不明确或 属性:&#39; WorkerAorB.WorkerAorB(System.Func&lt; A&gt;)&#39;和 &#39; WorkerAorB.WorkerAorB(System.Func&LT; B个)&#39;
WorkerAandB
给出了
错误CS0407:&#39;经理A.GetA()&#39;有错误的返回类型
在每种情况下,似乎编译器在传递对实际函数的引用而不是lambda或现有Func<A>
变量时,以及在{{{}}中变得无法确定要使用哪个重载。 1}} case明确地选择了WRONG重载,并给出了传递函数返回类型的错误。
WorkerAandB
class A { }
class B { }
class WorkerA
{
public WorkerA(Func<A> funcA) { }
}
class WorkerAorB
{
public WorkerAorB(Func<A> funcA) { }
public WorkerAorB(Func<B> funcB) { }
}
class WorkerAandB
{
public WorkerAandB(Func<A> funcA, Func<B> funcB = null) { }
public WorkerAandB(Func<B> funcB) { }
}
可以以某种方式修改class ManagerA
{
A GetA() { return new A(); }
static A GetAstatic() { return new A(); }
Func<A> GetAfunc = GetAstatic;
ManagerA()
{
new WorkerA(() => new A()); // ok
new WorkerA(GetA); // ok
new WorkerA(GetAstatic); // ok
new WorkerAorB(() => new A()); // ok
new WorkerAorB(() => new B()); // ok
new WorkerAorB(GetA); // error CS0121
new WorkerAorB(GetAstatic); // error CS0121
new WorkerAorB(() => GetA()); // ok
new WorkerAorB(GetAfunc); // ok
new WorkerAandB(() => new A()); // ok
new WorkerAandB(GetA); // error CS0407
new WorkerAandB(GetAstatic); // error CS0407
new WorkerAandB(GetA, null); // ok
new WorkerAandB(GetAstatic, null); // ok
new WorkerAandB(GetAfunc); // ok
}
}
// class ManagerB or ManagerAandB left as an exercise to the reader!
或GetA
函数以帮助编译器识别要使用的正确重载,或者只是在此上下文中允许使用lambdas和/或显式声明的委托吗? / p>
更新:我从示例中省略了一些信息。在真实中 问题,班级
GetAstatic
和A
实际上是相关的。B
此外,在进一步反映真实问题时,请致电
class B : A { }
像
public WorkerAandB(Func<B> funcB) { }
实际上相当于
new WorkerAandB(GetB)
所以对于真正的问题,我已经完成了相同的删除 示例问题中的第二个构造函数,因为事实证明重载是多余的。
与此同时,我接受了实际上有潜力的答案 问题的解决方案(虽然是一个明显的问题,我没有提及 在最初的问题中),即使它不是我最终使用的。
答案 0 :(得分:2)
Eric Lippert的回答here的关键部分,因为它适用于这个问题,似乎是“开销解决方案不考虑返回类型”。因此,如果您通过用Func
替换每个Action
来重写示例,则错误消失,因为现在存在非空参数列表,通过该列表可以解决歧义。
class A { }
class B { }
class WorkerA
{
public WorkerA(Action<A> doA) { }
}
class WorkerAorB
{
public WorkerAorB(Action<A> doA) { }
public WorkerAorB(Action<B> doB) { }
}
class WorkerAandB
{
public WorkerAandB(Action<A> doA, Action<B> doB = null) { }
public WorkerAandB(Action<B> doB) { }
}
class ManagerA
{
void DoA(A a) { }
static void DoAstatic(A a) { }
Action<A> DoAfunc = DoAstatic;
ManagerA()
{
new WorkerA((A a) => { }); // ok
new WorkerA(DoA); // ok
new WorkerA(DoAstatic); // ok
new WorkerAorB((A a) => { }); // ok
new WorkerAorB((B b) => { }); // ok
new WorkerAorB(DoA); // ok
new WorkerAorB(DoAstatic); // ok
new WorkerAorB(a => { }); // ok
new WorkerAorB(DoAfunc); // ok
new WorkerAandB(a => { }); // ok
new WorkerAandB(DoA); // ok
new WorkerAandB(DoAstatic); // ok
new WorkerAandB(DoA, null); // ok
new WorkerAandB(DoAstatic, null); // ok
new WorkerAandB(DoAfunc); // ok
}
}
答案 1 :(得分:1)
答案是:
public ManagerA()
{
new WorkerA(() => new A()); // ok
new WorkerA(GetA); // ok
new WorkerA(GetAstatic); // ok
new WorkerAorB(() => new A()); // ok
new WorkerAorB(() => new B()); // ok
new WorkerAorB((Func<A>)GetA); // cast to avoid error CS0121
new WorkerAorB((Func<A>)GetAstatic); // cast to avoid error CS0121
new WorkerAorB(() => GetA()); // ok
new WorkerAorB(GetAfunc); // ok
new WorkerAandB(() => new A()); // ok
new WorkerAandB((Func<A>)GetA); // cast to avoid error CS0407
new WorkerAandB((Func<A>)GetAstatic); // cast to avoid error CS0407
new WorkerAandB(GetA, null); // ok
new WorkerAandB(GetAstatic, null); // ok
new WorkerAandB(GetAfunc); // ok
}
至于为什么没有强制转换后它没有工作....似乎编译器GetA不是来自Func<A>
类型而只是method group
答案 2 :(得分:0)
整体问题是你为什么要编写这样的代码?我看到问题的假设性质,但它不应该存在于现实世界中,因为我们应该编写实际按预期读取的函数:
public Person GetPersonById(func<int> personIdFunc)
没有其他方法可以编写一个函数来通过传入一个返回int的函数来获取ID。
或者在创建多个构造函数时,使用正确的面向对象方法可以解决问题:
class Person
{
public Person(Func<B> funcB)
:this(null, funcB)
{ }
public Person(Func<A> funcA, Func<B> funcB) { }
}
但直接针对你的问题..
可以以某种方式修改GetA或GetAstatic函数以帮助编译器识别要使用的正确重载,或者只是在此上下文中允许使用lambdas和/或显式声明的委托吗?
据我所知,它不能在函数定义上,但它可以在它的使用上完成:
new WorkerAorB((Func<A>)GetA); // error CS0121
new WorkerAorB((Func<A>)GetAstatic); // error CS0121
new WorkerAandB((Func<A>)GetA); // error CS0407
new WorkerAandB((Func<A>)GetAstatic); // error CS0407