This is a mirror of official site: http://jasper-net.blogspot.com/

Generics: The Better Method Match

| Sunday, February 26, 2012
This topic came up again in on one of the C# developer mailing lists I participate in.  Because there is still a reasonable amount of confusion on this topic, I thought I would post the rules and the reason behind those rules here.

Everything from this post is taken from Sections 7.5.2 (Type Inference) 7.5.3 (Overload Resolution) in the C# Language Specification (4th edition).

Consider these two overloads of a Log method:

static void Log<K,V>(K key, V value)
static void Log<K,V>(string key, IDictionary<K, V> values)

Suppose you called it with the following code:

class FooDict : Dictionary<string, int>
{
}

// create custom dictionary
FooDict fooDict = new FooDict();

// should *not* use the IDictionary<K,V>
Log("FooDict", fooDict);

// try a regular dictionary value
Dictionary<string, int> dict = fooDict;

// should *not* use the IDictionary<K,V>
Log("Dictionary", dict);

// now try the EXACT type
IDictionary<string, int> idict = fooDict;

// should use the IDictionary<K,V> - does
Log("IDictionary", idict);

The comments do explain what happens. But why?

Before doing anything else, the compiler searches for all the possible candidate methods for any method call. That list of candidate methods may include generic methods.  If the method call does not specify the type parameters, the compiler must infer them. Eric Lippert’s annotation in the spec is very pertinent here (emphasis his):

    The type inference algorithm is designed to answer one question: Given only the arguments and the formal parameter types, what is the best possible type arguments that can be inferred for each type parameter?

In the first case, Log<string, FooDict> is the best possible type arguments that can be inferred.

Now we come to the overload resolution algorithm.  There are two candidate methods. Using the inferred type parameters, the first is a better match, because it is an identify conversion: Log<string, FooDict> is an identity conversion from Log<string, FooDict>. In the second case, there is an implicit conversion from Log<string, FooDict> to Log<string, IDictionary<string, int>>, because FooDict implements IDictionary<string, int>. The identity conversion is a better match than a conversion to an interface.

Read more: SRT Solutions
QR: Inline image 1

Posted via email from Jasper-net

0 comments: