Direct overload resolution

I'm having trouble getting the compiler to fix the correct overload for the extension method. The best way to explain me a little code. Here's a LINQPad script that demonstrates the problem. This does not compile due to the problem I am facing:

void Main(){
    new Container<A>().Foo(a=>false);
}

interface IMarker{}
class A : IMarker{
    public int AProp{get;set;}
}
class B : IMarker{
    public int BProp{get;set;}
}
class Container<T>{}

static class Extensions{
    public static void Foo<T>(this T t, Func<T, bool> func)
        where T : IMarker{
        string.Format("Foo({0}:IMarker)", typeof(T).Name).Dump();
    }
    public static void Foo<T>(this Container<T> t, Func<T, bool> func){
        string.Format("Foo(Container<{0}>)", typeof(T).Name).Dump();
    }
}

The error I am getting is:

The call is ambiguous between the following methods or properties: ' Extensions.Foo<Container<A>>(Container<A>, System.Func<Container<A>,bool>)' and ' Extensions.Foo<A>(Container<A>, System.Func<A,bool>)'

It seems to me that this is not ambiguous. The first method will not take value Container<T>, but only IMarker. It seems that the general restrictions do not help in overload resolution, but in this version of the code they look like this:

void Main(){
    new A().Bar();
    new A().Foo(a=>a.AProp == 0);
    new A().Foo(a=>false); // even this works
    new A().Foo(a=>{
        var x = a.AProp + 1;
        return false;
    });

    new Container<A>().Bar();
    new Container<A>().Foo(a=>a.AProp == 0);
    new Container<A>().Foo(a=>{
        var x = a.AProp + 1;
        return false;
    });
}

interface IMarker{}
class A : IMarker{
    public int AProp{get;set;}
}
class B : IMarker{
    public int BProp{get;set;}
}
class Container<T>{}

static class Extensions{
    public static void Foo<T>(this T t, Func<T, bool> func)
        where T : IMarker{
        string.Format("Foo({0}:IMarker)", typeof(T).Name).Dump();
    }
    public static void Foo<T>(this Container<T> t, Func<T, bool> func){
        string.Format("Foo(Container<{0}>)", typeof(T).Name).Dump();
    }

    public static void Bar<T>(this T t) where T : IMarker{
        string.Format("Bar({0}:IMarker)", typeof(T).Name).Dump();
    }
    public static void Bar<T>(this Container<T> t){
        string.Format("Bar(Container<{0}>)", typeof(T).Name).Dump();
    }
}

This compiles and produces the expected results:

(A: IMarker)
Foo (A: IMarker)
Foo (A: IMarker)
Foo (A: IMarker)
( <A> )
Foo ( <A> )
Foo ( & , A > )

, , , Container<T>. Bar , . Foo , , . , , , .

, ? - , ? # 4, # 6.

+4
2

, ! =) , where T:IMaker ( ). lambda, :

  • :

    new Container<A>().Foo(a => a.AProp == 0);
    

    , a: A;

  • :

    new Container<A>().Foo(a => a != null);
    

    .

, " Foo" (Func) , .

(25.6.4) :

(§14.5.5.1) . , , . , inferred type .

, inferred type . , . . , , - .

"". , :

  • Bar(Container<A>) new Container<A>() ( IMaker)
  • Bar(A) new A() ( )

ECMA-334, . 100%, , , .

+5

, , , , . :

void Main(){
    new A().Bar();
    new A().Foo(a=>a.AProp == 0);
    new A().Foo(a=>false);

    new Container<A>().Bar();
    new Container<A>().Foo(a=>a.AProp == 0);
    new Container<A>().Foo(a=>false); // yay, works now!
}

interface IMarker<T>{
    T Source{get;}
}

class A : IMarker<A>{
    public int AProp {get;set;}
    public A   Source{get{return this;}}
}
class B : IMarker<B>{
    public int BProp {get;set;}
    public B   Source{get{return this;}}
}

class Container<T> : IMarker<T>{
    public T Source{get;set;}
}

static class Extensions{
    public static void Foo<T>(this IMarker<T> t, Func<T, bool> func){}
    public static void Bar<T>(this IMarker<T> t){}
}

, . , , , .

+1

Source: https://habr.com/ru/post/1649086/


All Articles