Welcome to OGeek Q&A Community for programmer and developer-Open, Learning and Share
Welcome To Ask or Share your Answers For Others

Categories

0 votes
736 views
in Technique[技术] by (71.8m points)

c# - Overload resolution issue for generic method with constraints

A code sample:

interface IFoo { }
class FooImpl : IFoo { }

static void Bar<T>(IEnumerable<T> value)
    where T : IFoo
{
}

static void Bar<T>(T source)
    where T : IFoo
{
}

Can anybody explain, why this method call:

var value = new FooImpl[0];
Bar(value);

targets Bar<T>(T source) (and, hence, doesn't compile)?

Does compiler take into account type parameter constraints at all, when resolving overloads?

UPD.

To avoid confusion with arrays. This happens with any implementation of IEnumerable<T>, e.g.:

var value = new List<FooImpl>();

UPD 2.

@ken2k mentioned covariance. But let's forget about FooImpl. This:

var value = new List<IFoo>();
Bar(value);

produces the same error.
I'm sure, that implicit conversion between List<IFoo> and IEnumerable<IFoo> exists, since I can easily write something like this:

static void SomeMethod(IEnumerable<IFoo> sequence) {}

and pass value into it:

SomeMethod(value);
See Question&Answers more detail:os

与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…
Welcome To Ask or Share your Answers For Others

1 Reply

0 votes
by (71.8m points)

Does compiler take into account type parameter constraints at all, when resolving overloads?

No, because generic constraints are not part of the function signature. You can verify this by adding a Bar overload that is identical except for the generic constraints:

interface IBar { }

static void Bar<T>(IEnumerable<T> value)
    where T : IFoo
{
}

static void Bar<T>(T source)
    where T : IBar
{
    // fails to compile : Type ____ already defines a member called 'Bar' with the same parameter types
}

The reason your code doesn't compile is because the compiler chooses the "best" match based on the method signature, then tries to apply the generic constraints.

One possible reason why it doesn't is because this call would be ambiguous:

{suppose List<T> had an Add<T>(IEnumerable<T> source) method}

List<object> junk = new List<object>();
junk.Add(1);   // OK
junk.Add("xyzzy") // OK
junk.Add(new [] {1, 2, 3, 4});  //ambiguous - do you intend to add the _array_ or the _contents_ of the array?

The obvious fix is to use a different name for the Bar method that takes a collection (as is done in the BCL with Add and AddRange.


与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…
OGeek|极客中国-欢迎来到极客的世界,一个免费开放的程序员编程交流平台!开放,进步,分享!让技术改变生活,让极客改变未来! Welcome to OGeek Q&A Community for programmer and developer-Open, Learning and Share
Click Here to Ask a Question

...