原文链接: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中如何查找脚本挂载在哪个物体上