繁体   English   中英

使用泛型和隐式转换重载解析

[英]Overload resolution with generics and implicit conversion

此代码未编译:

static class Foo
{
    public static Bar Do(Func<Bar> f) => null;
    public static Bar<TOut> Do<TOut>(Func<Bar<TOut>> f) => null;
}

public class Bar
{
}

public class Bar<TOut>
{
    public static implicit operator Bar<TOut>(TOut i) => null;
}

// Here compiler complains:
// CS0029 Cannot implicitly convert type 'int' to 'Bar'
// CS1662 Cannot convert lambda expression to intended delegate type 
// because some of the return types in the block
// are not implicitly convertible to the delegate return type
Foo.Do(() => 1);

我的期望是编译器会看到 lambda 的返回类型,并且除非int转换为Bar<int>否则无法选择有效的重载。 但是,我看到编译器解析为第一种方法。

规范的哪一部分定义了这种行为?

这是在Method Invocations 中指定的,当规范讨论哪种方法声明可以作为重载决议的候选者时,对于M(A)形式的调用:

构造方法调用的候选方法集。 对于与方法组M关联的每个方法F

  • 如果F是非泛型的,则在以下情况下F是候选对象:
    • M没有类型参数列表,并且
    • F适用于A
  • 如果F是泛型且M没有类型参数列表,则在以下情况下F是候选对象:
    • 类型推断成功,推断出调用的类型参数列表,并且
    • [...]

仅从这些规则中,我们可以看到非泛型Do候选对象,而泛型Do不是,因为类型推断失败。 尝试注释掉非通用的Do ,你会看到它说“不能推断类型参数”。

我没有完整的答案,但我有一些观察:

观察 1 :删除非通用版本的Do

static class Foo
{
    public static Bar Do(Func<Bar> f) => null;
}

public class Bar
{
    public static implicit operator Bar(int i) => null;
}

// CS0411: The type arguments for method 'Foo.Do<TOut>(Func<Bar<TOut>>)' cannot be inferred from the usage. Try specifying the type arguments explicitly.
Foo.Do(() => 1);

,编译器仍然无法解析Func<Bar<TOut>> f 因此,问题似乎不在于选择错误的重载,而是编译器根本无法将() => 1Func<Bar<TOut>> f隐式匹配。

观察 2 :下面的代码有效

static class Foo
{
    public static Bar Do(Func<Bar> f) => null;
}

public class Bar
{
    public static implicit operator Bar(int i) => null;
}

Foo.Do(() => 1);

这表明编译器正在检查隐式转换。

观察 3 :使隐式转换运算符将int作为输入,尽管使运算符实际上不可用,因为TOut不会被解析,使编译器找到运算符:

static class Foo
{
    public static Bar<TOut> Do<TOut>(Func<Bar<TOut>> f) => null;
}

public class Bar<TOut>
{
    public static implicit operator Bar<TOut>(int i) => null; // Input is `int` now
}
// CS0411: The type arguments for method 'Foo.Do<TOut>(Func<Bar<TOut>>)' cannot be inferred from the usage. Try specifying the type arguments explicitly.
Foo.Do(() => 1);

所以所有这些结合起来让我认为编译器只是没有尝试哪些泛型类型会导致隐式转换起作用。

暂无
暂无

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

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