zoukankan      html  css  js  c++  java
  • C#函数式程序设计之泛型(下)

    C#函数式程序设计之约束类型

    每当使用泛型类型时,可以通过where字句对泛型添加约束:

    static void OutputValue<T>(T value) where T : ListItem<string>
    {
          Console.WriteLine("String list value: {0}", value.Value);
    }
    

    这个例子直观地声明了一个约束:类型T必须与ListItem<string>相匹配。泛型类型约束T:X表示T可以是X、X的派生对象或X的实现(假如X是一个接口)。换言之,假如类型T的一个实例为t,则可以把它赋给一个变量:X x=t;

    约束可以使用具体的类型,但是在这些情形下,类型不可以是密封的。有几个特殊的关键字可以取代或补充类型声明符。关键字class表示此类型必须是一个引用类型,而struct表示它必须是一个值类型。当new()与class或者任何具体类型一起使用时,可以给这个类型定义一个默认的构造函数。

    约束的最后一个应用是定义两个类型参数的关系。例如,对于类型参数的T和U,约束T:U表示T必须与U相容。

    使用约束时,有一点必须记住:泛型的基本作用是提供一个类型安全的方法,使代码可以处理不同类型的数据。约束用得越多,则离这个思想越远,因为约束降低了灵活性。

    C#函数式程序设计之其他泛型类型

    除了方法与类外,结构体、委托和接口也可以使用类型参数。结构体和接口使用类型参数是显而易见的,其用法与类相似:

    public struct MyPoint<T> where T : struct
    {
          public MyPoint(T x, T y)
          {
                this.x = x;
                this.y = y;
          }
    
          private readonly T x;
          public T X
          {
               get
               {
                    return x;
               }
          }
    
          private readonly T y;
          public T Y
          {
               get
               {
                    return y;
               }
          }
    
          public interface IListItem<T>
          {
               T Value { get; }
                ListItem<T> Prepend(T value);
           }
    }
    

    即使是委托,其用法也丝毫没有令人吃惊的地方:

    public delegate R CreateDelegate<T, R>(T param);
    public class ParameterFactory<T, R>
    {
          CreateDelegate<T, R> createDelegate;
          public ParameterFactory(CreateDelegate<T, R> createDelegate)
          {
               this.createDelegate = createDelegate;
          }
    }
    

    使用了泛型后,这些委托几乎可以代表任何函数。

    C#函数式程序设计之协变与逆变

    如果一个操作保留了类型原来的顺序,则成为协变,如果颠倒它们的顺序,则称为逆变。所谓的类型顺序是指:通用类型的顺序值比专用类型的顺序值强。

    下面这个例子说明C#支持协变,首先定义一个对象数组:

    object[] objects = new object[3];
    objects[0] = new object();
    objects[1]="Just a string";
    objects[2]=10;
    

    可以把不同的值插入到这个数组中,因为所有数据最终都是派生自.NET中的Object类型。换言之,Object是一个非常通用的类型,即它是一个强类型。接下来说明.NET支持协变,它把一个弱类型的值赋给强类型的变量:

    string[] stringsTest = new string[] { "one", "two", "three" };
    objects = stringsTest;
    

    变量objects属于object[]类型,它可以保存实际类型为string[]的值。仔细想想,我们希望如此,但是结果不是这样的,毕竟,虽然string派生自object,但是string[]并不是派生自object[]。尽管如此,由于本例中C#支持协变,这个赋值是可行的。

    说明逆变思想需要一个比较复杂的例子:

    public class Person:IPerson
    {
        public Person() { }
    }
    
    public class Woman : Person
    {
        public Woman() { }
    }
    

    Woman是从Person派生出来的类,现在分析如下两个函数:

    static void WorkWithPerson(Person person)
    { }
    
    static void WorkWithWonman(Woman woman)
    { }
    

    其中一个函数作用于Woman类,另一个函数比较通用,作用于Person类。从Woman类可以定义以下两个委托和函数:

    delegate void AcceptWomanDelegate(Woman person);
    
    static void DoWork(Woman woman, AcceptWomanDelegate acceptWoman)
    {
         acceptWoman(woman);
    }
    

    DoWork函数接受一个Woman参数和一个函数引用,后者也接受一个Woman参数。DoWork函数把Woman实例传递给委托。元素类型大小为:Person比Woman强,WorkWithPerson比WorkWithWoman强,为了应用逆变,在此认为WorkWithPerson比AcceptWomanDelegate强,看以下三行代码:

    Woman woman = new Woman();
    DoWork(woman, WorkWithWonman);
    DoWork(woman, WorkWithPerson);
    

    首先创建一个Woman实例,然后调用DoWork函数,把Woman实例和WorkWithWoman方法的引用地址传递给DoWork。后者显然是与委托类型AcceptWomanDelegate相容——两者都只有一个Woman类型参数,没有返回值。但第三行代码有点怪,根据AcceptWomanDelegate的要求,WorkWithPerson方法接受一个Person参数,而不是一个Woman参数。虽然如此,WorkWithPerson还是与委托类型相容,这是逆变的缘故。

    因此,在委托类型下,强类型可以保存在弱类型的变量中。

    变异也能应用在泛型中。如下代码:

    List<object> objectList = new List<object>();
    List<string> stringList = new List<string>();
    objectList = stringList;
    

    以上代码并没有得到C#的支持,编译器会报如下错误:

    在C#和.NET4.0中,泛型的变异支持已删除,现在要使用泛型类型参数,可以用新增的关键字 in 和 out。这两个关键字定义或限制某个类型参数的数据流动方向,允许变异发生。

    作者:Ribbon 出处: http://www.cnblogs.com/Ribbon/ 本文版权归作者和博客园共有,欢迎转载。未经作者同意下,必须在文章页面明显标出原文链接及作者,否则保留追究法律责任的权利。 如果您认为这篇文章还不错或者有所收获,可以点击右下角的【推荐】按钮,因为你的支持是我继续写作,分享的最大动力!
  • 相关阅读:
    线段树专辑—— pku 1436 Horizontally Visible Segments
    线段树专辑——pku 3667 Hotel
    线段树专辑——hdu 1540 Tunnel Warfare
    线段树专辑—— hdu 1828 Picture
    线段树专辑—— hdu 1542 Atlantis
    线段树专辑 —— pku 2482 Stars in Your Window
    线段树专辑 —— pku 3225 Help with Intervals
    线段树专辑—— hdu 1255 覆盖的面积
    线段树专辑—— hdu 3016 Man Down
    Ajax跨域访问
  • 原文地址:https://www.cnblogs.com/Ribbon/p/3604339.html
Copyright © 2011-2022 走看看