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

Cam*_*ron 37 c# generics extension-methods .net-4.0 covariance

代码有点奇怪,所以忍受我(请记住这个场景确实出现在生产代码中).

说我有这个接口结构:

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

public interface IFoo<out T> where T : IBase {  }
Run Code Online (Sandbox Code Playgroud)

这个扩展方法类围绕接口构建:

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)
    {
    }
}
Run Code Online (Sandbox Code Playgroud)

为什么DoSomething编译中没有注释掉的行?编译器是非常高兴,让我分配foobar,这是同类型的通用约束,并呼吁该扩展方法来代替.没有扩展方法语法调用扩展方法也没问题.

任何人都可以确认这是一个错误或预期的行为吗?

谢谢!

仅供参考,这是编译错误(为清晰可读而删节的类型):

'TFoo'不包含'DoSomethingElse'的定义,最好的扩展方法重载'DoSomethingElse(IFoo)'有一些无效的参数

Jul*_*ain 9

引用C#规范:

7.6.5.2扩展方法调用

在其中一个表单的方法调用(第7.5.5.1节)中

expr.标识符()

expr.标识符(args)

expr.标识符<typeargs>()

expr.标识符<typeargs>(args)

如果调用的正常处理找不到适用的方法,则尝试将该构造作为扩展方法调用进行处理.如果expr或任何args具有编译时类型dynamic,则扩展方法将不适用.

目标是找到最佳的类型名称C,以便可以进行相应的静态方法调用:

C .标识符(expr)

C .identifier(expr,args)

C .标识符<typeargs>(expr)

C .标识符<typeargs>(expr,args)

在以下情况下,扩展方法Ci.Mj符合条件:

· Ci是非泛型的非嵌套类

· Mj的名称是标识符

· 当如上所示作为静态方法应用于参数时,Mj是可访问且适用的

·从exprMj的第一个参数的类型存在隐式标识,引用或装箱转换.

由于DoSomethingElse(foo)编译但foo.DoSomethingElse()没有,好像在重载编译器故障而延期方法:隐式引用转换从存在fooIFoo<IBase>.


ole*_*sii 5

你能在IFoo中定义DoSomethingElse吗?

public interface IFoo<out T> where T : IBase
{
    void DoSomethingElse();
}
Run Code Online (Sandbox Code Playgroud)

UPDATE

也许你可以改变签名

public static void DoSomethingElse(this IFoo<IBase> foo)
=>
public static void DoSomethingElse<TFoo>(this TFoo foo) 
    where TFoo : IFoo<IChild>
Run Code Online (Sandbox Code Playgroud)