C# study notes generic

Generic

Generic is an important concept in C#. Simply put, generic is to write a class that can target different types. That is, multiple data types can be operated on the same code through parameterized types. Generic programming is a programming paradigm that uses "parameterized types" to abstract types to achieve more flexible reuse. C# introduced generics in version 2.0.

Basic use of generics

Consider such a problem: If you want to define a collection of lists with multiple elements List, add it. Delete, search and other functions, but in order to indicate the type of element can be of various types (such as int, string, Point, Personetc.), if not applicable generic, there are two methods, one for each type of write once, such as:

class IntList{
    
    void Add(int a){
    
    ...}  bool Remove(int a){
    
    ...}}
class StringList{
    
    void Add(string a){
    
    ...}  bool Remove(string a){
    
    ...}}
class PointList{
    
    void Add(Point a){
    
    ...}  bool Remove(Point a){
    
    ...}}
class PersonList{
    
    void Add(Person a){
    
    ...}  bool Remove(Person a){
    
    ...}}

This is obviously too much trouble. Another way of writing is to write a objectcollection class for elements, such as:

class List{
    
    void Add(object a){
    
    ...}  bool Remove(object a){
    
    ...}}

The latter way of writing solves the problem that objectcan be targeted to any type, but the type information is removed. If an stringobject is added to an int set , the system does not know.
The way to solve this problem is to use generics, that is, add a "type parameter" to the above class to indicate the type of the element, so that it can target different types and specify the type at the same time. When defining types, use angle brackets to indicate type parameters:

class List<T>
{
    
    
	void Add(T a){
    
    ...}
	bool Remove(T a){
    
    ...}
}

Here T is the type parameter, which represents any type. In actual use, you only need to specify the type used, such as:

	List<int> list1 = new List<int>();  list1.Add(5);.
	List<string> list2 = new List<string>();  list2.Add("abc");
	List<Point> list3 = new List<Point>();  list3.Add(new Point());

Custom generics

1. Declaration of generic class

A class definition can specify a set of type parameters by adding a list of type parameter names enclosed in angle brackets after the class name. Type parameters can be used to define class members in the body of the class declaration. E.g:

public class Pair<TFirst, TSecond>
{
    
    
	public TFirst First;
	public TSecond Second;
}

When using a generic class, you must provide type arguments for each type parameter:

	Pair<int, string> pair = new Pair<int, string> (){
    
    }
	int i = pair.First;				// First is int
	string s = pair.Second;			// Second is string

According to habit, generic type parameters start with a capital letter T. If there is only one type parameter, there can be only one capital letter T.
Example: GenericStark.csCustomize a generic stack class.

using System;
public class MyStark<T>
{
    
    
	private T[] buffer;
	private int index = 0;
	private int size;

	public MyStark(int size = 100) {
    
    
		buffer = new T[size];
		this.size = size;
	}

	public void Push(T data) {
    
    
		if (index >= size) throw new Exception();
		buffer[index++] = data;
	}

	public T Pop() {
    
    
		if (index == 0) throw new Exception();
		return buffer[--index];
	}

	public bool IsEmpty() {
    
    
		return index == 0;
	}
}
class Program
{
    
    
	static void Main(){
    
    
		MyStark<string> stark = new MyStark<string>();
		stark.Push("aaa");
		stark.Push("bbbb");
		stark.Push("ccccc");
		while (!stark.IsEmpty()) {
    
    
			string a = stark.Pop();
			Console.WriteLine(a);
		}
	}
}

2. Generic structure, interface and generic method

The definition of generic structure and interface is similar to the definition of generic class. For generic methods, put the parameter type after the method name, for example:

	private static Random rnd = new Random();
	static T RandomOneOf<T>(T a, T b) {
    
    
		if (rnd.Next(2) == 0) return a;
		return b;
	}

When calling a generic method, you can add the actual parameter type, but in most cases, the compiler can infer the type. In this case, the angle brackets and the actual type can be omitted. The following two ways of writing can be done:

	string s1 = RandomOneOf<string>("aaa", "bbb");
	string s2 = RandomOneOf("ccc", "ddd");

Example: GenericMethod.cscustom generic method.

using System;
class GenericMethod
{
    
    
	public static void Shuffle<T>(T[] array) {
    
    
		Random rnd = new Random();
		for (int i = 1; i < array.Length; i++) {
    
    
			Swap<T>(array, i, rnd.Next(0, i));
		}
	}

	static void Swap<T>(T[] array, int indexA, int indexB) {
    
    
		T temp = array[indexA];
		array[indexA] = array[indexB];
		array[indexB] = temp;
	}
}
class Program
{
    
    
	static void Main(string[] args) {
    
    
		// 初始化牌局
		int[] array = new int[54];
		for (int i = 0; i < array.Length; i++) {
    
    
			array[i] = i;
		}

		// 洗牌
		GenericMethod.Shuffle<int>(array);

		// 显示
		foreach (int n in array) {
    
    
			Console.Write(n + " ");
		}
	}
}

3. Constraints on type parameters

When using generics, sometimes it is necessary to make the type parameters meet certain conditions, such as a certain type 1 and its subclasses. At this time, you need to use wherekeywords to constrain the type parameters. Such as:

class MyList<T>where T:Person

Indicates that the type parameter is a Personclass (and its subclasses).
Common constraints have the following forms:
Insert picture description here
In actual programming, if you want to use new T()this method to create an object in the program, you must add where T : new ()such constraints. If the program is to use type T null, it is required to use T : classsuch constraints. If the type is a class may also be value types, may be used default, the operator for the default value ( null, , 0), falsesuch as:

	T a = default(T);

It can be said that this defaultis specifically used to solve the problem of generic default values.
In the C#7.0 version, it can be written more simply:

	T a = default;

4. Out and in type parameters in generic interfaces

The definition of a generic interface is similar to the definition of a generic class, but in many cases, it is necessary to consider the wide adaptability of the interface and use two modifiers, outand in. If the parameter type is modified with out, the type can only be used as the return value of the method, and cannot be used as the parameter of the method; if modified with in, the type can only be used as the parameter of the method, and cannot be used as the return value of the method. The outmodified one is called covariant; the inmodified one is called contravariant; if it is not outand useless in, the type parameter is called invariant.
In the example below,

interface C <out X, in Y, Z>
{
    
    
	X M(Y y);
	Z P{
    
    get; set;}
}

XFor covariance, Yfor contravariance, and Zfor fixed. Covariance and contravariance are mainly to solve the problem of conversion between subclasses and parent classes.

Guess you like

Origin blog.csdn.net/qq_45349225/article/details/114011462