• 13.3.4 【接口和委托的泛型可变性】复杂情况


    1.  Converter<TInput, TOutput> :同时使用协变性和逆变性

                Converter<object, string> converter1 = x => x.ToString();
                Converter<string, string> converter2 = converter1;
                Converter<object, object> converter3 = converter1;
                Converter<string, object> converter4 = converter1;

    代码清单13-15展示了委托类型 Converter<object, string> (一个接收对象,生成字符串的委托)的可变性转换。我们首先使用简单的Lambda表达式(调用 ToString )实现了委托。
    我们恰巧从未真正调用该委托,因此完全可以使用空引用。但我发现如果可以定义一个在调用时发生的具体行为,将有助于理解可变性。接下来的两行代码相对简单,每次只需关注一种类型参数即可。 TInput 类型参数只用于输入,因此可以逆变地将 Converter<object,string> 当作 Converter<Button,string>来使用。换句话说,既然可以将任意对象的引用传递给转换器,那么自然可以传递一个Button引用。同样,TOutput类型参数只用于输出(返回类型),因此可以协变地使用它:如果转换器总是返回一个字符串引用,那么在你能够保证返回一个对象引用的地方,可以放心地使用该转换器。最后一行仅仅是对这种理念的一种合理延伸。它在同一个转换内同时使用了逆变性和协变性,得到的是一个只接受按钮并且返回对象引用的转换器。注意,如果不进行强制转换,则无法将其转换为原来的类型——我们已经基本上在每个点上都放松了要求,你不能再隐式地收紧了。

    2. 疯狂的高阶函数

            delegate Func<T> FuncFunc<out T>();
            delegate void ActionAction<out T>(Action<T> action);
            delegate void ActionFunc<in T>(Func<T> func);
            delegate Action<T> FuncAction<in T>();

    每一个声明都相当于将一个标准的委托嵌入到另一个之中。
    例如, FuncAction<T> 等同于Func<Action<T>> ,它们都表示一个函数,返回以 T 为参数的 Action 。但它应该是协变的还是逆变的呢?
    这个函数将返回与 T 相关的内容,似乎应该是协变的,但是它也传入了与 T 有关的内容,似乎又是逆变的。
    答案是该委托对 T 是逆变的,因此声明时使用了 in 修饰符。
    作为一个便捷的规则,可以认为内嵌的逆变性反转了之前的可变性,而协变性不会如此。
    因此 Action<Action<T>> 对 T 来说是协变的, Action<Action<Action<T>>> 是逆变的。
    相比之下,对于 Func<T> 的可变性来说,你可以编写 Func<Func<Func<... Func<T>...>>> ,嵌套任意多个级别,得到的仍然是协变性。
    举一个使用接口的类似示例,假设可以使用比较器对序列进行比较。如果能够比较任意对象的两个序列,自然可以比较两个字符串序列,但反之则不然。
    将其转换为代码(不必实现接口)如下:

                IComparer<IEnumerable<object>> objectComparer = null;
                IComparer<IEnumerable<string>> stringComparer = objectComparer;

    这种转换是合法的:由于 IEnumerable<T> 的协变性,IEnumerable<string> 是比IEnumerable<object> 更“小”的类型;
    而 IComparer<T> 的逆变性可以将“较大”类型的比较器转换为较小类型的比较器。
    当然,我们在本节只使用了包含单个类型参数的委托和接口——它也完全可以应用于多个类型参数。
    尽管这种类型的可变性让你痛不欲生,不过不必担心,你并不会频繁地使用它,而且用的时候编译器也会帮你大忙。
    我只是想让你知道有这种可能。另一方面,你可能认为某些功能可以实现,但实际上它们并没有得到支持。

  • 相关阅读:
    用ruby抓取网页
    [转] 从项目管理角度看敏捷开发
    ruby学习笔记(9)
    [转] 从项目管理角度看敏捷开发
    ruby学习笔记(8)
    ruby学习笔记(7)
    [转] 什么是敏捷开发
    netbeans tomcat
    maven
    jersey
  • 原文地址:https://www.cnblogs.com/kikyoqiang/p/10111324.html
Copyright © 2020-2023  润新知