简体   繁体   English

c#通用重载方法调度模糊

[英]c# Generic overloaded method dispatching ambiguous

I just hit a situation where a method dispatch was ambiguous and wondered if anyone could explain on what basis the compiler (.NET 4.0.30319) chooses what overload to call 我刚刚遇到一个方法调度模糊的情况,并想知道是否有人可以解释编译器(.NET 4.0.30319)选择什么过载调用的基础

interface IfaceA
{

}

interface IfaceB<T>
{
    void Add(IfaceA a);
    T Add(T t);
}

class ConcreteA : IfaceA
{

}

class abstract BaseClassB<T> : IfaceB<T>
{
    public virtual T Add(T t) { ... }
    public virtual void Add(IfaceA a) { ... }
}

class ConcreteB : BaseClassB<IfaceA>
{
    // does not override one of the relevant methods
}

void code()  
{
    var concreteB = new ConcreteB();

    // it will call void Add(IfaceA a)
    concreteB.Add(new ConcreteA());
}

In any case, why does the compiler not warn me or even why does it compile? 在任何情况下,为什么编译器不会警告我,甚至为什么编译? Thank you very much for any answers. 非常感谢您的任何答案。

It follows the rules in section 7.5.3.2 of the C# 4 specification ("Better function member"). 它遵循C#4规范 (“更好的功能成员”)第7.5.3.2节中的规则。

First (well, after seeing that both methods are applicable ) we need to check the conversions from argument types to parameter types. 首先(在看到两种方法都适用之后 ),我们需要检查从参数类型到参数类型的转换。 In this case it's reasonably simple because there's only one argument. 在这种情况下,它相当简单,因为只有一个参数。 Neither conversion of argument type to parameter type is "better" because both are converting from ConcreteA to IfaceA . 参数类型到参数类型的转换都不是“更好”,因为它们都是从ConcreteA转换为IfaceA It therefore moves on to the next set of criteria, including this: 因此,它转向下一组标准,包括:

Otherwise, if MP has more specific parameter types than MQ, then MP is better than MQ. 否则,如果MP具有比MQ更多的特定参数类型,则MP优于MQ。 Let {R1, R2, …, RN} and {S1, S2, …, SN} represent the uninstantiated and unexpanded parameter types of MP and MQ. 设{R1,R2,...,RN}和{S1,S2,...,SN}表示MP和MQ的未实例化和未展开的参数类型。 MP's parameter types are more specific than MQ's if, for each parameter, RX is not less specific than SX, and, for at least one parameter, RX is more specific than SX:specific than SX: MP的参数类型比MQ更具体,如果对于每个参数,RX的特定性不低于SX,并且对于至少一个参数,RX比SX更具体:特定于SX:

  • A type parameter is less specific than a non-type parameter. 类型参数不是非类型参数的特定参数。
  • ... ...

So even though the conversion is equally good, the overload using IfaceA directly (rather than via delegates) is deemed "better" because a parameter of type IfaceA is more specific than a parameter of type T . 因此即使转换同样好,直接使用IfaceA (而不是通过委托)的过载也被认为是“更好”,因为IfaceA类型的参数比类型T的参数更具体。

There's no way of getting the compiler to warn on this behaviour - it's just normal overload resolution. 没有办法让编译器警告这种行为 - 这只是正常的重载决议。

Because the compiler chooses the most specific first. 因为编译器首先选择最具体的。

What happens if you call like so: 如果你这样打电话怎么办:

void code()   
{ 
    var concreteB = new ConcreteB(); 

    IfaceA  x = concreteB.Add(new ConcreteA()); 
} 

This somewhat reminds me of the "Type inference a-go-go" in Jon Skeet's BrainTeaser . 这有点让我想起Jon Skeet的BrainTeaser中的“类型推断a-go-go”。 If you do not want to trust the compiler, you might want to force its choice by calling Add<ConcreteA>(new ConcreteA()) 如果您不想信任编译器,可能需要通过调用Add<ConcreteA>(new ConcreteA())来强制选择它。

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

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