泛型用符号“T”来定义。“T”代表 任意合法的类型。书中通常称之为泛型类型。 对这个T(任意类型)的限定,赋予其它功能。构成了泛型的主要内容和难点。
一、泛型基本定义
1、泛型类
public class MyClass<T>{}
2、泛型接口
public interface ImyInterface<T>{}
3、泛型结构
public struct MyStruct<T>{}
4、泛型方法.可以在非泛型类中定义
void Swap<T>(){}
二、约束 对T的限定
public class DocumentManager<T>
where T: IDocument //说明T这个任意类型,继承了IDocument 接口。这样可以把documentQueue集合中所有实现了IDocument接口的对象,赋值给IDocument 接口变量。(多态)
public void DisplayAllDocuments() { foreach (T doc in documentQueue) { Console.WriteLine(doc.Title); //这条语句其实是 Console.WriteLine((IDocument)doc.Title); 将doc强制转为IDocument类型。 编译器支持语法糖。可以不用写这个了。
} }
三、协变 逆变
1. 仅有泛型接口和泛型委托支持对类型参数的可变性,泛型类或泛型方法是不支持的。
2. 值类型不参与协变或反变,IFoo<int>永远无法变成IFoo<object>,不管有无声明out。因为.NET泛型,每个值类型会生成专属的封闭构造类型,与引用类型版本不兼容。
3. 声明属性时要注意,可读写的属性会将类型同时用于参数和返回值。因此只有只读属性才允许使用out类型参数,只写属性能够使用in参数。
Rectangle继承与Shape
static void Main() { IIndex<Rectangle> rectangles = RectangleCollection.GetRectangles();//创建了一个新的对象 IIndex<Shape> shapes = rectangles; //子泛型接口 赋值给 父泛型接口 for (int i = 0; i < shapes.Count; i++) { Console.WriteLine(shapes[i]); } IDisplay<Shape> shapeDisplay = new ShapeDisplay();//创建一个对象,这个对象需要传递一个shape对象,用于显示 IDisplay<Rectangle> rectangleDisplay = shapeDisplay; // 父泛型接口 赋值给 子泛型接口 传递一个tectangle对象也当然可以了 rectangleDisplay.Show(rectangles[0]); Console.ReadKey(); }
子类可以变为父类,子泛型接口也可以变为父泛型接口,称之为协变的泛型接口(无此概念,但可以这么理解)(主要指 返回值)
父类不可以变为子类(一般情况),但子泛型接口却可以赋值给父泛型接口,称之为逆变的泛型接口。(主要指 参数)
协变和逆变,更加抽象,可以建立更加抽象的模型和软件架构。但是用起来的时候,规则较多。在计算机编程领域并不是一个好的方法和逻辑。应该抛弃,用另一种更加抽象的逻辑来替代,个人建议不用学习这个语法。不符合思维本性。思维本身应该是不断的归类,简化才对。觉得抽象出泛型就可以了,再往上,就有点复杂了。也没有必要。面向对象编程,已经是对自然的一种契合。不能再走入过去的路子了。编程语言应该贴近思维习惯,贴近人类经验的框架才对。不满足的全部应该淘汰。