错误的重载导致编译器错误

时间:2015-04-17 17:42:59

标签: c# lambda overload-resolution member-functions

使用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>

  

更新:我从示例中省略了一些信息。在真实中   问题,班级GetAstaticA实际上是相关的。

B
     

此外,在进一步反映真实问题时,请致电

class B : A { }
     

public WorkerAandB(Func<B> funcB) { }
     

实际上相当于

    new WorkerAandB(GetB)
     

所以对于真正的问题,我已经完成了相同的删除   示例问题中的第二个构造函数,因为事实证明重载是多余的。

     

与此同时,我接受了实际上有潜力的答案   问题的解决方案(虽然是一个明显的问题,我没有提及   在最初的问题中),即使它不是我最终使用的。

3 个答案:

答案 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