原文鏈接:https://blog.csdn.net/khqxf/article/details/88554247
有了泛型,可減少object對象的使用,對object進行裝箱/拆箱時,性能不及泛型
1. 允許多種類型共享一組代碼。在聲明泛型時,給出類型參數,然后用不同類型創建實例。也就是在事先使用類型占位符,在實例化時才指出真實類型。
2. **泛型五種類型**:類、接口、結構、委托和方法。泛型是類型的模板,而類型是對象的模板。
3. 利用泛型實現棧的操作:
```
//泛型的基本用法
using System;
namespace test28
{
class Program
{
//利用泛型實現棧的操作
class Myclass<T> //聲明泛型,T,S為類型占位符
{
T[] StackArray;
int StackPointer = 0;
public void Push(T x)
{
if(!IsStackFull)
StackArray[StackPointer++] = x;
}
public T Pop()
{
return (!IsStackEmpty)?StackArray[--StackPointer]:StackArray[0];
}
const int MaxStack = 10;
bool IsStackFull {get{return StackPointer >= MaxStack;}}
bool IsStackEmpty {get{return StackPointer <= 0;}}
public Myclass()
{
StackArray = new T[MaxStack];
}
public void Print()
{
for(int i = StackPointer -1;i>=0;i--)
{
Console.WriteLine(" Info:{0}",StackArray[i]);
}
}
}
static void Main(string[] args)
{
Myclass<int> StackInt = new Myclass<int>();
Myclass<string> StackString = new Myclass<string>();
StackInt.Push(6);
StackInt.Push(8);
StackInt.Push(10);
StackInt.Print();
StackString.Push("加油!2019!");
StackString.Push("自動化1401班!");
StackString.Print();
}
}
}
```
**類型參數的約束**:使用where子句對類型參數進行約束,where子句之間沒有標點符號,如果某個類型參數有多個約束,在每一個where子句中用逗號間隔。`where TypeParams:constraint,constraint,...`示例如下
```
class Myclass<T1,T2>
where T1:Custom
where T2:IComparable
{
...
}
```
5 約束類型和次序
類名:只有這個類型的類或者從它繼承的類才能用作類型實參
class:任何引用類型,包括類、數組、委托和接口都可以用作類型實參。
struct:任何值類型都可以用作類型實參。
接口名:只有這個接口或者實現這個接口的類型才可以用作類型實參。
new():任何帶有無參公共構造函數的類型都可以用作類型實參,即為構造函數約束。
6 where子句的約束必須有一定的順序,最多只能有一個主約束;可以有任意多的接口名約束;如果存在構造函數約束,則必須放在最后。
```
class SortedList<S>
where S:IComparable<S>{....}
class LinkedList<M,N>
where M:IComparable<M>
where N:IComparable{....}
class MyDictionary<KeyType,ValueType>
where Keytype:IEnumerable,
new() {...}
```
7、泛型方法:它有兩個參數列表,位于圓括號里的方法參數列表,位于尖括號里的類型參數列表。要聲明泛型方法,要在方法名之后一次是類型參數列表和方法列表,在方法參數列表后是可選的約束子句
```
public void PrintData<S,T>(S p,T t)
where S:Person
{
...
}
```
8 調用泛型方法: 在方法調用時提供類型實參,Mymethod<short,int>();Mymethod<int,long>();當然,這里也可用推斷類型,倘若方法參數列表的類型已知,編輯器可以推斷出類型參數列表的情況,這是就可以將類型參數列表給忽略,int myint = 5;Mymethod<int>(myint);可簡寫為Mymethod(myint);
泛型方法示例
```
class Simple //非泛型類
{
static public void ReverseAndPrint<T>(T[] arr) //泛型方法
{
Array.Reverse(arr);
foreach(T item in arr)
{
Console.WriteLine("{0},",item.ToString());
}
Console.WriteLine(" ");
}
}
class Program
{
static void Main()
{
//創建各種類型的數組
var intArray = new int[]{3,5,7,9};
var stringArray = new string[]{"first","second","third"};
var doubleArray = new double[]{3.456,4.567,5.678};
Simple.ReverseAndPrint<int>(intArray); //調用方法
Simple.ReverseAndPrint(intArray); //推斷引用
Simple.ReverseAndPrint<string>(stringArray); //調用方法
Simple.ReverseAndPrint(intArray); //推斷引用
Simple.ReverseAndPrint<double>(doubleArray); //調用方法
Simple.ReverseAndPrint(doubleArray); //推斷引用
}
}
```
擴展方法和泛型類:將泛型類與擴展方法結合,允許我們將類中的靜態方法關聯到不同的泛型上,還可以像調用類結構實例那樣調用方法。泛型類的擴展方法必須聲明為static;必須是靜態類的成員;第一個參數類型必須為this,后面是擴展的泛型類的名稱,示例如下:
```
//擴展方法和泛型類
using System;
namespace test30
{
static class ExtendHoleder
{
public static void Print<T>(this Holder<T> h)
{
T[] vals = h.GetValues();
Console.WriteLine("{0},\t{1},\t{2}",vals[0],vals[1],vals[2]);
}
}
class Holder<T>
{
T[] vals = new T[3];
public Holder(T t0,T t1,T t2)
{vals[0]=t0;vals[1]=t1;vals[2]=t2;}
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();
}
}
}
```
泛型結構:與泛型類相似,泛型結構可以有類型參數和約束。泛型結構的規則和條件與泛型類是一樣的。示例如下
```
//泛型結構
using System;
namespace test31
{
struct PieceOfData<T>
{
public PieceOfData(T value){_data = value;}
private T _data;
public T Data
{
get{return _data;}
set{_data = value;}
}
}
class Program
{
static void Main(string[] args)
{
var intData = new PieceOfData<int>(16);
var stringData = new PieceOfData<string>("hi nihao!");
Console.WriteLine("intData ={0}",intData.Data);
Console.WriteLine("stringData ={0}",stringData.Data);
}
}
}
```
泛型委托:泛型委托與非泛型委托相似,只是類型參數決定了能接受什么樣的方法。要聲明泛型委托,在委托名之后要有類型參數列表和委托參數列表;類型參數包括返回值、形參列表和約束子句。示例如下,泛型委托與泛型類。
```
//泛型委托的簡單示例
using System;
namespace test32
{
delegate T PrintT<T>(T t); //聲明泛型委托,返回類型和參數列表類型都是T
public class Myclass<T> //聲明泛型類
{
public T Method(T t) //方法的參數和返回類型與委托匹配
{
return t;
}
}
class Program
{
static void Main(string[] args)
{
Myclass<string> mycl = new Myclass<string>();
PrintT<string> prt = new PrintT<string>(mycl.Method); //等價于PrintT<string> prt = mycl.Method; 創建委托對象并賦值給委托變量
Console.WriteLine(prt("越努力越幸運,加油,自動化1401班!")); //執行委托
}
}
}
```
泛型委托示例二,注意,此示例是泛型委托和非泛型類的使用。
```
//泛型委托示例二
using System;
namespace test33
{
delegate T3 SumNum<T1,T2,T3>(T1 t1,T2 t2); //聲明泛型委托,返回類型為T3,類型參數為T1,T2,T3,委托參數為T1,T2
public class Myclass //聲明非泛型類
{
private int _data;
public string Method(int t1,int t2) //泛型方法的參數與返回類型與委托匹配
{
_data = t1 + t2;
return _data.ToString();
}
}
class Program
{
static void Main(string[] args)
{
Myclass mycl = new Myclass();
SumNum<int,int,string> sumn = new SumNum<int,int,string>(mycl.Method); //創建委托對象并賦值給委托變量
Console.WriteLine(sumn(4,5)); //執行委托
}
}
}
```
泛型接口:泛型接口的類型參數決定了接口成員的參數類型和返回類型。在接口名后跟類型參數;泛型接口既可以在泛型類中實現也可以在非泛型類中實現;實現不同類型參數的泛型接口是不同的接口;泛型接口的實現必須唯一,不能重復實現相同的接口。
泛型接口示例:
```
//泛型接口示例一
using System;
namespace test34
{
class Program
{
public interface Multify<T> //聲明泛型接口
{T Mulfy(T t);}
public class Myclass<T>: Multify<T> //在泛型類中實現泛型接口
{
public T Mulfy(T t)
{
return t;
}
}
static void Main(string[] args)
{
Myclass<int> mycl = new Myclass<int>();
Console.WriteLine(mycl.Mulfy(16));
}
}
}
```
代碼過于簡單,只是為了演示,結果是16
協變與逆變:協變允許將派生類的委托對象賦值給基類變量,逆變則與之相反;當然協變和逆變都可用于接口;協變的(委托或接口)類型參數必須聲明為輸出參數(關鍵字out),逆變的類型參數必須聲明為輸入參數(關鍵字in),在實現委托方法時,如果是協變,則方法的參數傳入派生類的引用,實現派生類的方法;如果是逆變,傳入基類的引用,實現基類的成員;協變的委托沒有委托參數,逆變的委托有委托參數。
委托的協變和逆變示例:
```
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace test35
{
class Myclass //聲明基類
{
public string[] color = {"red","blue","yellow","orange","green"};
}
class Myderived : Myclass {} //聲明派生類
class Program
{
delegate void Mydele<out T>(); //聲明泛型委托,協變時不能有委托參數,類型參數有out修飾
delegate void Mydele1<in T>(T t); //聲明泛型委托,逆變時有委托參數,類型參數有in修飾
public static void Method() //協變,方法要與委托Mydele相匹配,在方法中實現派生類
{
Myderived mydr = new Myderived();
Array.Reverse(mydr.color); //將數組倒序排列
foreach(string item in mydr.color)
{
Console.WriteLine(item);
}
}
public static void Method1(Myclass mycl) //逆變,要與委托Mydele1相匹配,傳入基類的引用,實現基類的成員
{
foreach(string item in mycl.color)
{
Console.WriteLine(item);
}
}
static void Main(string[] args)
{
Console.WriteLine("................協變................");
Mydele<Myderived> mydel = Method; //創建委托對象
Mydele<Myclass> mycl = mydel; //協變時,將派生類的委托對象賦值給基類的委托變量是可行的
mycl(); //執行委托
Console.WriteLine("................逆變................");
Mydele1<Myclass> mycll = Method1; //創建委托對象
Mydele1<Myderived> mydell = mycll; //逆變時,將基類的委托對象賦值給派生類的委托變量是可行的
mydell(new Myderived()); //執行委托,傳入派生類的對象
}
}
}
```
19. 接口的協變示例:
```
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace test36
{
//接口的協變
class Animal{public string Name;} //聲明基類
class Dog:Animal{}; //聲明派生類
interface IMyIfc<out T> //聲明泛型接口
{
T GetFirst();
}
class SimpleReturn<T>:IMyIfc<T> //聲明泛型類,實現泛型接口
{
public T[] items = new T[2];
public T GetFirst(){return items[0];}
}
class Program
{
static void DoSomething(IMyIfc<Animal> returner) //傳入接口的引用
{
Console.WriteLine(returner.GetFirst().Name);
}
static void Main(string[] args)
{
SimpleReturn<Dog> dogReturner = new SimpleReturn<Dog>();
dogReturner.items[0] = new Dog(){Name = "WorkHarding"};
IMyIfc<Animal> animalReturner = dogReturner;
DoSomething(dogReturner);
}
}
}
```
接口的逆變示例:
```
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace test37
{
//接口的逆變
class Mybase
{
public string[] str = {"red","orange","yellow","green","blue","violet"};
}
class Myderived : Mybase{}
interface IMyIfc<in T> //定義泛型接口,并且接口沒有返回類型
{
string GetFirst();
}
class MyColor<T>:IMyIfc<T> //在泛型類中實現接口
{
public string[] Color = new string[6] ;
public string GetFirst()
{
Myderived mydr = new Myderived();
for(int i = 0;i<6;i++)
{
Color[i] = mydr.str[i];
}
return Color[0];
}
}
class Program
{
public static void Choice(IMyIfc<Myderived> t) //傳入接口的引用
{
Console.WriteLine(t.GetFirst());
}
static void Main(string[] args)
{
MyColor<Mybase> myco = new MyColor<Mybase>();
IMyIfc<Myderived> t = myco;
Choice(myco);
}
}
}
```
- C#
- 基礎 System
- 命名規范
- 變量
- 數據類型
- 值類型
- 簡單類型
- 整數類型
- 字符類型
- 浮點類型
- 布爾類型
- 枚舉類型
- 結構體類型
- 引用類型
- 類類型
- 對象(Object)類型
- 字符串(String)類型
- 方法屬性
- 動態(Dynamic)類型
- 數組類型
- 接口Interface
- 委托類型delegate
- 裝箱和拆箱
- 指針類型
- 值類型與引用類型的區別
- Var類型
- 類型轉換
- 隱式轉換
- 顯式轉換
- 常量
- 常用函數
- 流程控制
- 循環
- 跳轉語句
- 數組
- 數組查找
- 添加組元素
- 復制與克隆數組
- 刪除數組元素
- 數組排序與反轉
- 數組排序
- 冒泡排序
- 直接插入排序
- 選擇排序法
- 數組對象
- 哈希表
- 其他
- 遞歸
- 屬性與方法及方法重載
- 結構與類
- 類
- 構造函數與析構函數
- 繼承
- 多態
- 泛型
- demo
- 漢字字符(串)比較
- 創建指定大小文件與讀取大文件
- 小截屏軟件功能
- 子窗體返回主窗體
- 判斷是否為數字
- 獲得字符串實際長度(包括中文字符)
- unity
- script腳本
- 腳本的生命周期
- 調試
- Unity Manual5.4
- Unity手冊
- Working In Unity
- Unity 2D
- Graphics(圖形)
- Physics(物理系統)
- Scripting(腳本)
- Multiplayer and Networking(多玩家和聯網)
- Audio(音頻)
- Animation(動畫)
- UI
- Navigation and Pathfinding(導航和尋路)
- Unity Services(Unity服務)
- Virtual Reality(虛擬現實VR)
- Open-source repositories(開源代碼庫)
- Platform-specific(特定于平臺的信息)
- Legacy Topics(舊版主題)
- Expert Guides(專家指南)
- 重要的類
- Object
- GameObject(重要)
- Component
- Transform(重要)
- Rigidbody
- ParticleSystem
- Behaviour
- Camera
- Animator
- AudioSource
- Animation
- AudioListener
- Light
- MonoBehaviour事件行為(重要)
- Terrain
- Collider
- Renderer
- Texture
- Mesh
- material
- Time
- Prefab預制件
- 功能demo
- 層級未知查找子物體
- 查找hp最小的敵人
- 查找最近的敵人
- 小項目之英雄無敵
- 界面操作
- Scene窗口
- Game窗口
- project窗口
- Hierarchy窗口
- 動畫
- Animation重要API
- 2D
- Sprite(creator) Sprite Renderer
- Sprite Editor
- Sprite Packer(遺留功能)
- 排序組組件
- 切片精靈
- 精靈遮罩
- 精靈圖集
- Tilemap
- 2D物理系統
- 全局設置(Project setting)
- 2D剛體(Rigidbody 2D)
- 碰撞(事件)消息
- 2D碰撞體(Collider 2D)
- 2D圓形碰撞體(Circle Collider 2D)
- 2D盒型碰撞體(BoxCollider 2D)
- 2D多邊形碰撞體( Polygon Collider 2D)
- 2D邊界碰撞體(EdgeCollider 2D)
- 2D膠囊碰撞體(CapsuleCollider 2D)
- 2D復合碰撞體(Composite Collider 2D)
- 2D物理材質(摩擦和彈性)(Physics Material 2D)
- 2D關節
- 2D距離關節(Distance Joint 2D)
- 2D固定關節(Fixed Joint 2D)
- 2D摩擦關節(Friction Joint 2D)
- 2D鉸鏈關節(Hinge Joint 2D)
- 2D相對關節(Relative Joint 2D)
- 2D滑動關節(Slider Joint 2D)
- 2D彈簧關節(Spring Joint 2D)
- 2D目標關節(Target Joint 2D)
- 2D車輪關節(Wheel Joint 2D)
- 2D恒定力(Constant Force 2D)
- 2D 效應
- 2D區域效應(AreaEffector 2D)
- 2D浮力效應(BuoyancyEffector 2D)
- 2D點效應(PointEffector 2D)
- 2D平臺效應(PlatformEffector 2D)
- 2D表面效應(SurfaceEffector 2D)
- 精靈動畫
- 2D動畫事件
- 重要類
- rigidbody2d
- 小竅門
- Unity中如何查找腳本掛載在哪個物體上