zoukankan      html  css  js  c++  java
  • 泛型:更好的匹配方法【翻译】

    原文地址: 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)");
    
            }
    
        }
  • 相关阅读:
    Linux命令之_Cut(转)
    Use “error_messages” in Rails 3.2? (raises “undefined method” error)
    ruby错误
    Linux SvN操作
    Linux 安装SVN服务器 (转)
    删除 vim 命令
    vscode 配置java开发
    java json
    svn
    采样率和比特率
  • 原文地址:https://www.cnblogs.com/yangbingqi/p/2377235.html
Copyright © 2011-2022 走看看