c# - 为什么这个通用扩展方法不能编译?

标签 c# generics .net-4.0 extension-methods covariance

代码有点奇怪,所以请耐心等待(请记住,这种情况确实出现在生产代码中)。

假设我有这个接口(interface)结构:

public interface IBase {  }
public interface IChild : IBase {  }

public interface IFoo<out T> where T : IBase {  }

使用围绕接口(interface)构建的扩展方法类:

public static class FooExt
{
    public static void DoSomething<TFoo>(this TFoo foo)
        where TFoo : IFoo<IChild>
    {
        IFoo<IChild> bar = foo;

        //foo.DoSomethingElse();    // Doesn't compile -- why not?
        bar.DoSomethingElse();      // OK
        DoSomethingElse(foo);       // Also OK!
    }

    public static void DoSomethingElse(this IFoo<IBase> foo)
    {
    }
}

为什么 DoSomething 中注释掉的行不能编译?编译器非常乐意让我将 foo 分配给 bar,它与通用约束具有相同的类型,并改为调用扩展方法。没有扩展方法语法调用扩展方法也是没问题的。

任何人都可以确认这是错误还是预期的行为?

谢谢!

仅供引用,这是编译错误(为便于阅读而删节的类型):

'TFoo' does not contain a definition for 'DoSomethingElse' and the best extension method overload 'DoSomethingElse(IFoo)' has some invalid arguments

最佳答案

引用 C# 规范:

7.6.5.2 Extension method invocations

In a method invocation (§7.5.5.1) of one of the forms

expr . identifier ( )

expr . identifier ( args )

expr . identifier < typeargs > ( )

expr . identifier < typeargs > ( args )

if the normal processing of the invocation finds no applicable methods, an attempt is made to process the construct as an extension method invocation. If expr or any of the args has compile-time type dynamic, extension methods will not apply.

The objective is to find the best type-name C, so that the corresponding static method invocation can take place:

C . identifier ( expr )

C . identifier ( expr , args )

C . identifier < typeargs > ( expr )

C . identifier < typeargs > ( expr , args )

An extension method Ci.Mj is eligible if:

· Ci is a non-generic, non-nested class

· The name of Mj is identifier

· Mj is accessible and applicable when applied to the arguments as a static method as shown above

· An implicit identity, reference or boxing conversion exists from expr to the type of the first parameter of Mj.

DoSomethingElse(foo)编译但foo.DoSomethingElse()没有,它似乎是扩展方法重载解析中的编译器错误:隐式引用转换存在于 fooIFoo<IBase> .

关于c# - 为什么这个通用扩展方法不能编译?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/6034871/

相关文章:

c# - 必需的属性和 JSON 属性名称

java - 如何将整数元素添加到泛型通配符的ArrayList中?

.net - .NET 4.0 是否存在 mdbg 托管调试器示例?

multithreading - .net 4.0 任务 : Synchronize on one or more objects

.net - 无法在 infer.net fun 中加载 FSharp.Core 版本 4.0.0//dll 中的硬链接(hard link)依赖项?

c# - Mono 对待 System.Data.SqlCommands 的方式是否与 .NET 不同?

c# - 如何从 gridview 将多条记录添加到 SQL Server 表中?

c# - 从 Web 服务反序列化大型 JSON 对象(内存不足)

c#泛型基类方法返回派生类的类型

java - 无法仅为 Enum 创建通用 javax validator