简体   繁体   English

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

[英]Wrong overload giving compiler error

Using VS2013, in the following example two different errors are given when attempting to pass a function to a worker's constructor, yet, lambda functions with the same prototype are ok. 使用VS2013,在下面的示例中,在尝试将函数传递给worker的构造函数时会给出两个不同的错误,但是,具有相同原型的lambda函数是可以的。

What am I doing wrong, and how can I change the definition of the GetA function to allow it to be passed? 我做错了什么,如何更改GetA函数的定义以允许它被传递?

In order to avoid confusion with similar-sounding questions caused by misunderstanding how class inheritance works, I've intentionally avoided any inheritance in this example. 为了避免因误解类继承如何工作而引起的类似问题的混淆,我在这个例子中故意避免任何继承。

WorkerA can only accept a Func<A> in it's contructor. WorkerA只能接受它的构造WorkerA中的Func<A> WorkerAorB is more flexible, and can accept either a Func<A> or a Func<B> . WorkerAorB更灵活,可以接受Func<A>Func<B> WorkerAandB is the most capable, and can accept a Func<A> and a Func<B> simultaneously (or either). WorkerAandB是最强大的,并且可以同时接受Func<A>Func<B> It is the closest to my real code. 它最接近我的真实代码。

However, when code in the manager attempts to instantiate workers, WorkerA works as expected, but WorkerAorB gives the error: 但是,当管理器中的代码尝试实例化worker时, WorkerA按预期工作,但WorkerAorB给出错误:

error CS0121: The call is ambiguous between the following methods or properties: 'WorkerAorB.WorkerAorB(System.Func<A>)' and 'WorkerAorB.WorkerAorB(System.Func<B>)' 错误CS0121:以下方法或属性之间的调用不明确:'WorkerAorB.WorkerAorB(System.Func <A>)'和'WorkerAorB.WorkerAorB(System.Func <B>)'

WorkerAandB gives WorkerAandB给出了

error CS0407: 'A ManagerA.GetA()' has the wrong return type 错误CS0407:'ManagerA.GetA()'的返回类型错误

In each case, it seems that the compiler becomes unable to determine which overload to use when it is being passed a reference to a real function rather than a lambda or an existing Func<A> variable, and in the WorkerAandB case it is unambiguously selecting the WRONG overload, and giving an error about the return type of the passed function. 在每种情况下,似乎编译器在传递对实际函数的引用而不是lambda或现有的Func<A>变量时无法确定要使用哪个重载,而在WorkerAandB情况下,它明确地选择它WRONG重载,并给出有关传递函数的返回类型的错误。

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!

Can the GetA or GetAstatic functions be modified in some way to help the compiler recognise the correct overload to use, or are only lambdas and/or explicitly-declared delegates allowed in this context? 是否可以通过某种方式修改GetAGetAstatic函数以帮助编译器识别要使用的正确重载,或者只是在此上下文中允许使用lambdas和/或显式声明的委托?

Update: Some information that I'd omitted from the example. 更新:我从示例中省略了一些信息。 In the real problem, classes A and B are in fact related. 在真正的问题中, A类和B类实际上是相关的。

 class B : A { } 

Also, on further reflection of the real problem, a call to 此外,在进一步反映真正的问题,呼吁

 public WorkerAandB(Func<B> funcB) { } 

like 喜欢

  new WorkerAandB(GetB) 

was in fact equivalent to 实际上相当于

  new WorkerAandB(GetB, GetB) 

So for the real problem, I've done the equivalent of deleting the second constructor in the example problem, as it turns out the overload was redundant. 所以对于真正的问题,我已经完成了相同的删除示例问题中的第二个构造函数,因为事实证明重载是多余的。

In the meantime I've accepted the answer that actually gave a potential solution to the problem (albeit an obvious one that I'd omitted to mention in the original question), even though it wasn't what I eventually used. 与此同时,我接受了实际上给出问题的潜在解决方案的答案(尽管在原始问题中我忽略了一个明显的答案),尽管它不是我最终使用的。

The key part of Eric Lippert's answer here , as it applies to this question, appears to be that "overhead resolution does not consider return types." Eric Lippert 在这里的答案的关键部分,因为它适用于这个问题,似乎是“开销分辨率不考虑返回类型”。 So if you rewrite your example by replacing every Func with an Action , the errors disappear, as now there are non-empty argument lists by which the ambiguity is resolved. 因此,如果通过用Action替换每个Func重写示例,则错误消失,因为现在存在非空参数列表,通过该列表可以解决歧义。

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

The answer would be this : 答案是这样的:

    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
    }

As for why it didn't work without the casts.... Seems that for the compiler GetA is not from the type Func<A> but only a method group 至于为什么没有强制转换后它不起作用....似乎编译器GetA不是来自类型Func<A>而只是一个method group

The overall problem is that why would you write code like this? 总的问题是你为什么要编写这样的代码? I see the hypothetical nature of the problem, but it shouldn't ever exist in the real world because we should write functions that actually read as expected: 我看到了问题的假设性质,但它不应该存在于现实世界中,因为我们应该编写实际按预期读取的函数:

public Person GetPersonById(func<int> personIdFunc)

there is no other way to write a function to Get a person by ID by passing in a function that returns an int. 没有其他方法可以通过传入一个返回int的函数来编写一个函数来通过ID获取一个人。

Or when creating multiple constructors, using the correct object oriented approach solves a problem: 或者在创建多个构造函数时,使用正确的面向对象方法解决了一个问题:

class Person
{
  public Person(Func<B> funcB) 
    :this(null, funcB)
  { }
  public Person(Func<A> funcA, Func<B> funcB) { }
}

But directly to your question.. 但直接问你的问题..

Can the GetA or GetAstatic functions be modified in some way to help the compiler recognise the correct overload to use, or are only lambdas and/or explicitly-declared delegates allowed in this context? 是否可以通过某种方式修改GetA或GetAstatic函数以帮助编译器识别要使用的正确重载,或者只是在此上下文中允许使用lambdas和/或显式声明的委托?

As far as I am aware it cannot on the function definitions, but it can be done on it's use: 据我所知,它不能在函数定义上,但它可以在它的使用上完成:

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

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM