泛型:更好的匹配方法【翻译】

原文地址: http://www.srtsolutions.com/generics-the-better-method-match?utm_source=feedburner&utm_medium=feed&utm_campaign=Feed%3A+billwagner+%28Bill+Blogs+in+C%23%29

 

这个问题又出现在我参与分享的一个C#开发人员邮件列表中。因为还有这一主题的合理数量混乱,我想我会发布规则以及这些规则背后的原因。

 

这里发布的所有东西都来自<<C#语言规范>>(第四版)  7.5.2节(类型引用) 和7.5.3节(重载解析).

 

考虑这两个Log的重载方法:

    

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

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

假如你调用下列代码:

 

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);
 
注释描述了代码的调用执行情况,为什么会有这样的结果?
 
作任何操作执行之前,编译器会先寻找所有合适的候选方法,那些候选方法可能包括泛型方法。如果方法调用不指定参数具体类型,编译器就会推断参数类型。Eric Lippert在说明的解释已经很详细了(如下)
类型推断规则被设计成回答一个问题:仅给定实参和形式参数类型,什么是最合适的实参被推断成每个类型参数。
对于第一个重载方法,Log<string, FooDict>是推断出最匹配的参数类型。现在分析下重载的运算规则,有两个候选方法。使用类型推断,第一个重载方法更匹配,因为调用第一个重载方法是确定转换:Log<string, FooDict> 是一个来自于Log<string, FooDict>的确定转换,调用第二个重载方法则是一个继承转换,Log<string, FooDict> 到Log<string, IDictionary<string, int>>的继承转换,因为FooDict类继承IDictionary<string, int>接口。确定转换优先于接口转换。
同样的处理逻辑可以应用于其它的继承转换:比如转换成父类,长度转换(如int类型转成long类型)或者用户定义类继承转换。
 
引用规范和说”就是这样工作运行的”是一样的,但是为什么这是正确的选择对于编程语言来说呢?简略地说,因为接口类型在真正编译的时候类型转换才起作用(注:泛型是生成后就已经起作用了)。 我完成的部分已经发布到这里 C# Puzzlers Live Lessons
 
 
以下是本人写的完整的测试运行代码
class Program

    {

        static void Main(string[] args)

        {

            // create custom dictionary

            FooDict fooDict = new FooDict();

            // should *not* use the IDictionary<K,V>

            Logger.Log("FooDict", fooDict);

            // try a regular dictionary value

            Dictionary<string, int> dict = fooDict;

            // should *not* use the IDictionary<K,V> 

            Logger.Log("Dictionary", dict);

            // now try the EXACT type

            IDictionary<string, int> idict = fooDict;

            // should use the IDictionary<K,V> - does

            Logger.Log("IDictionary", idict);

        }

    }

     class FooDict : Dictionary<string, int>

    {

    }

    class Logger

    { 

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

        {

            Console.WriteLine("call:Log<K, V>(string key, IDictionary<K, V> values)");

        }

        public static void Log<K, V>(K key, V value)

        {

            Console.WriteLine("call:Log<K,V>(K key, V value)");

        }

    }

你可能感兴趣的:(泛型)