Chapter 2 generic
1. Static members of generic classes
Static members of a generic class can only be shared in one instance of the class.
public class staticDemo<T> { public static int x; }
Because both a string type and an int type use the staticDemo <T> class, there are two sets of static fields:
StaticDemo <string>. x = 4; staticDemo <int>. x = 5; Console. WriteLine (staticDemo <string>. x); // output 4
2. covariation and resistance: refers to the conversion of parameters and return values.
Assume there are Shape and Rectangle classes, and Rectangle is derived from the Shape base class. The Display () method is declared to accept an object of the Shape type as its parameter:
(1)
Public void Display (Shape o ){}
---- Now you can pass any object derived from the Shape base class. Because Rectangle is derived from the Shape base class, the Rectangle satisfies all the Shape requirements. The Compiler accepts the call of this method:
Rectangle r = new Rectangle {Width = 5, Height = 2.5 };
Display (r); // Child class to parent class, role of covariant
(2)
When the method returns a Shape, it cannot be given a Rectangle, because the Shape is not always a Rectangle. The opposite is feasible:
Public Rectangle GetRectangle ();
Shape s = GetRectangle ();
For the above (1) (2) behavior, before. net4, this behavior method is not applicable to generics. However, in. net4, the Extended Language supports the coordination and resistance of generic interfaces and generic delegation.
That is, it can be like this: ITest <Shape> shape = ITest <Rectangle> rectangle; // covariant
A. covariant: The subclass changes to the parent class --------------- the parameter type is covariant.
B. Do not change: if the parent class changes to a subclass, the return type of the --------------- method may not be successful.
3. covariant of generic Interfaces
If the generic type is marked with the out keyword, the generic interface is the covariant. This also means that the return type can only be T. The following IIndex and type T are changed collaboratively, And this type is returned from a read-only index.
public interface IIndex<out T> { T this[int index]{get;} int Count{get;} }
The RectangleCollection class is used to implement interface IIndex <out T>. The RectangleCollection class defines Rectangle for generic type T:
public class RectangleCollection: IIndex< Rectangle > { public static Rectangle[] data = new Rectangle[3] { new Rectangle { Height=2, Width=5}, new Rectangle { Height=3, Width=7}, new Rectangle { Height=4.5, Width=2.9} }; public static RectangleCollection GetRectangles() { return new RectangleCollection(); } public Rectangle this[int index] { get { if (index < 0 || index > data.Length) throw new ArgumentOutOfRangeException("index"); return data[index]; } } public int Count { get { return data.Length; } } }
---- As shown above, RectangleCollection. GetRectangles () returns a RectangleCollection class that implements the IIndex <Rectangle> interface. Therefore, you can assign the return value to the Rectangle variable of the IIndex <rectangle> type.
Because the interface is covariant, you can also assign the return value to a variable of the IIndex <Shape> type. [Rectangle inherits from 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]); } }
4. Resistance to changes to generic Interfaces
If the generic type is marked with the in keyword, the generic interface is variable-resistant. In this way, the interface can only use generic type T as the parameter type of its method, but cannot be used as the return value type of its method.
Public interface IDisplay <in T> {void Show (T item);} The ShapeDisplay class implements IDisplay <Shape> and uses the Shape object as the input parameter: public class ShapeDisplay: IDisplay <Shape> {public void Show (Shape s) {Console. writeLine ("{0} Width: {1}, Height: {2}", s. getType (). name, s. width, s. height) ;}---- create a new instance of ShapeDisplay, and return IDisplay <Shape> and assign it to the shapeDisplay variable. Because IDisplay <T> is variable-resistant, you can assign the result to IDisplay <Rectangle>, where the Rectangle class is derived from Shape. Static void Main (){//... IDisplay <Shape> s = new ShapeDisplay (); IDisplay <Rectangle> r = s; // change resistance. The parent class changes to rectangleDisplay In the subclass direction. show (RectangleCollection. data [0]);}