CSharp(C#) Language_Advanced (Generic Collection)

What is generic

  The generic feature provides a more elegant way to allow multiple types to share a set of code. Allow us to declare generic parameters of the type (type-parameterized) code, it may be instances of different types. In other words, we can use "type placeholders" to write code, and then specify the real type when creating an instance of the class

Generics in C#

  • C# provides 5 generic types: class, structure, interface, delegate and method.The first four are types and methods are members
    Generic types are templates for types
    Generic types are templates for types
    Generic and user-defined types
    Generic and user-defined types

Generic class

  Generic classes are not actual classes, but class templates , so we must first construct the actual class types from them, and then create an instance of this constructed class type

  • Use placeholders on certain types to declare a class
  • Provide the real type for the placeholder. In this way, there is a definition of the real class, which fills all the "vacancies". This type is called a constructed type (constructedtype)
  • Create instances of constructed types

Create an instance from a generic type
Create an instance from a generic type

Declare a generic class

Declaring a simple generic class is similar to declaring a normal class

The differences are as follows:

  • Put a set of angle brackets after the class name
  • Placeholder strings separated by commas in angle brackets to indicate the desired type. This is called type parameter (typcparameter)
  • Use type parameters in the body of a generic class declaration to indicate the type that should be replaced
//				  类型参数
class SomeClass < T1, T2 >
{
    
    
	// T1、T2表示在当前位置使用类型
	public T1 SomeVar = new T1();
	public T2 OtherVar = new T2();
}

Create construction type

  Once the generic type is created, we need to tell the compiler which real types can be used in place of placeholders (type parameters). The compiler obtains these real types and creates a constructed type (a template used to create a real class object)
  . The syntax for creating a constructed type is as follows, including listing the class name and providing the real type in angle brackets instead of type parameters. The real type to replace the type parameter is called type argument (typeargument) The difference between
SomeClass < short, int >Insert picture description here
type parameter and type argument (below)
Insert picture description here

Create variables and instances

MyNonGenClass 			 myNGC = new MyNonGenClass			 ();
//		构造类								 构造类
SomeClass < short, int > mySc1 = new SomeClass < short, int >();
var 					 mySc2 = new SomeClass < short, int >();

ps:Many different class types can be constructed from the same generic class. Each has a separate class type, as if they all have independent non-generic declarations

The difference between non-generic stack and generic stack

- Non-generic Generic
Source code size Bigger: we need to write a new implementation for each type Smaller: Regardless of the number of construction types, we only need one implementation
Executable size Regardless of whether each version of the stack will be used, it will appear in the compiled version Only types with structural types appear in executable files
Ease of writing Easy to write because it is more specific More difficult to write because it is more abstract
Ease of maintenance More prone to problems, because all modifications need to be applied to every available type Easy to maintain, because only one place needs to be modified

Type parameter constraints

Constraints are listed using the where clause

  • Each constrained type parameter has its own where clause
  • If the parameter has multiple constraints, they are separated by commas in the where clause
    where 参数类型 : 约束1, 约束2, ...

The main points of the where clause:

  • They are listed after the closing angle bracket in the type parameter list
  • They are not separated by commas or other symbols
  • They can be listed in any order
  • where is a contextual keyword, so it can be used in other contexts

Constraint type and order

Class name Only classes of this type or classes inherited from it can be used as type arguments
class Any reference type, including classes, arrays, delegates and interfaces can be used as type arguments
struct Any value type can be used as a type argument
Interface name Only this interface or the type that implements this interface can be used as a type argument
new() Any type with a public constructor without parameters can be used as type arguments. This is called a constructor constraint

ps: The where clause can be listed in any order. However, the constraints in the where clause must have a specific order

  • There can be at most one primary constraint, if there is one, it must be placed first
  • There can be any number of interface name constraints
  • If there is a constructor constraint, it must be placed last

Generic method

  Unlike other generics, methods are members, not types. Generic methods may be generic and non-generic structures and interface declarations
Generic methods can be declared in non-generic types of generic types
statements generic method
  with an optional type parameter list and constraint generic method

  • The generic method has two parameter lists
    • List of method parameters enclosed in parentheses
    • List of type parameters enclosed in angle brackets
  • To declare a generic method, you need:
    • Put the type parameter list after the method name and before the method parameters
    • Place optional constraint clauses after the method parameter list

eg:

public void PrintData <S, T>(string str, int t) where S:Person
{
    
    
	...
}

Calling a generic method
  To call a generic method, the type argument should be provided when the method is called
  MyMethod <short,int>();

Examples of generic methods

class Simple 										// 非泛型类
{
    
    
	static public void ReverseAndPrint<T>(T[] arr)  // 泛型方法
	{
    
    
		Array.Reverse(arr);
		foreach (T iten in arr) 					// 使用类型参T
		Console.krite("(0),", item.ToString());
		Console.Mriteline(*);
	}
}

class Program
{
    
    
	static void Kain()
	{
    
    
		//创建各种类型的数糕
		var intArray … new int[] {
    
    3, 5, 7, 9, 11 };
		var stringArray - new string[] {
    
     "first", "second", "third" };
		var doubleArray * nex double[]{
    
     3.567, 7.891, 2.345 };
		
		Simple.ReverseAndPrintcint>(intArray); 		 // 调用方法
		Simple.ReverseAndPrint(intArray); 			 // 推断类型并调用
		
		Simple.ReverseAndPrint<string>(stringArray); // 调用方法
		Simple.ReverseAndPrint(stringArray); 		 // 推断类型并调用
		
		Simple.ReverseAndPrintcdouble>(doubleArray); // 调用方法
		Simple.ReverseAndPrint(doubleArray); 		 // 推断类型并调用
	}
}

The result of the above case:

  11, 9, 7, 5, 3
  3, 5, 7, 9, 11

  third, second, first
  first, second, third

  2.345, 7.891
  , 3.567 3.567, 7.891, 2.345

Extension methods and generic classes

Extension methods of generic classes :

  • Must be declared as static
  • Must be a member of static class
  • There must be the keyword this in the first parameter type, followed by the name of the extended generic class

Case

static class ExtendHolder
{
    
    
	public static void Print<T>(this Holder<T> h)
	{
    
    
		T[] vals= h.GetValues();
 		Console.NriteLine("{0},\t{1},\t{2}",vals[0], vals[1],vals[2]);
 	}
 }
 
class Holder<T>
{
    
    
	T[] Vals = new T[3];
	
	public Holder(T V0, T V1,T v2)
	{
    
    
		vals[0] = v0;
		Vals[1] = v1;
		Vals[2] = v2;
	}
	public T[] GetValues() 
	{
    
     
		return Vals;
	}
	
class Program
{
    
    
	static void Main(string[] args) 
	{
    
    
		var intHolder = new Holder<int>(3, 5, 7);
		var stringHolder = new Holder<string>("a1", "b2", "c3");
		intHolder.Print();
		stringHolder.Print();
	}
}

Result of the above case:

3, 5, 7
a1, b2, c3

Generic structure

  • Similar to generic classes, the generic structure can have type parameters and constraints
  • The rules and conditions of the paradigm structure are the same as the generic class

Case

struct PieceOfData<T> //泛型结构
{
    
    
	public PieceOfData(T value)
	{
    
     
		_data = value;
	}
	
	private T _data;
	public T Data
	{
    
    
		set _data = value;
	{
    
    
}

class Program
{
    
    
	static void Main() 
	{
    
    
							  // 构造类型
		var intData = new Piece0fData<int>(10);
								//		构造类型
		var stringData = new PieceOfData<string>("Hi there.");

		Console.WriteLine("intData = {0}", intData.Data);
		Console.WriteLine("stringData = {0}", stringData.Data);
	}
}

Case result:

intData = 10
stringData = Hi there

Generic delegate

  • Generic delegates and non-generic delegates are very similar, but the type parameter determines what methods can be accepted
    • To declare a generic delegate, place the type parameter list in angle brackets after the delegate name and before the delegate parameter list

Case

delegate void MyDelegate<T>(T value); 				// 泛型委托
class Simple
{
    
    
	static public void PrintString(string s) 		// 方法匹配委托
	{
    
    
		Console.WriteLine(s);
	}
	static public void PrintUpperString(string s) 	// 方法匹配委托
	{
    
    
		Console.MriteLine("(O)",s.ToUpper());
	}
}

class Program
{
    
    
	static void Main()
	{
    
    
		//创建委托的实例
		var myDel = new MyDelegate<string>(Simple.PrintString);
		//添加方法
		myDel += Simple.PrintUpperString; 
		//调用委托
		myDel("Hi There.");
	}
}

Case result:

Hi There
Hi There

Generic interface

  Generic interfaces allow us to write interfaces whose parameters and interface member return types are generic type parameters. The declaration of a generic interface is similar to the declaration of a non-generic interface, but the type parameters need to be placed in angle brackets after the interface name

Case

interface IMyIfc<T>	// 泛型接口
{
    
    
	T RetrnIt( T inValue);
}

//      类型参数  泛型接口
class Simple<S> :IMyIfc<S> // 泛型类
{
    
     
	public S ReturnIt(S inValue) //实现泛型接口
	{
    
     
		return inValue
	}
}

class Program
{
    
    
	static void Main()
	{
    
    
		var trivInt = new Simple<int>();
		var trivString = new Simple<string>();

		Console.WriteLine("{0)",trivInt.ReturnIt(5));
		Console.NriteLine("{o)",trivString.ReturnIt("Hi there."));
	}
}

Case result:

5
Hi there.

ps: The implementation of the generic interface must be unique

Guess you like

Origin blog.csdn.net/qq_43562262/article/details/106019344