Unity基础之C#进阶篇笔记2:泛型
泛型
1.泛型是什么
//泛型实现了类型参数化,达到代码重用目的
//通过类型参数化来实现同一份代码上操作多种类型
//泛型相当于类型占位符
//定义类或方法时使用替代符代表变量类型
//当真正使用类或者方法时再具体指定类型
2.泛型分类
//泛型类和泛型接口
//基本语法:
//class 类名<泛型占位字母>
//interface 接口名<泛型占位字母>
//泛型函数
//基本语法:函数名<泛型占位字母>(参数列表)
//注意:泛型占位字母可以有多个,用逗号分开
3.泛型类和接口
class TestClass<T>
{
public T value;
}
class TestClass2<T1,T2,K,M,LL,Key,Value>
{
public T1 value1;
public T2 value2;
public K value3;
public M value4;
public LL value5;
public Key value6;
public Value value7;
}
interface TestInterface<T>
{
T Value
{
get;
set;
}
}
class Test : TestInterface<int>
{
public int Value { get => throw new NotImplementedException(); set => throw new NotImplementedException(); }
}
4.泛型方法
//1.普通类中的泛型方法
class Test2
{
public void TestFun<T>( T value)
{
Console.WriteLine(value);
}
public void TestFun<T>()
{
//用泛型类型 在里面做一些逻辑处理
T t = default(T);
}
public T TestFun<T>(string v)
{
return default(T);
}
public void TestFun<T,K,M>(T t, K k, M m)
{
}
}
//2.泛型类中的泛型方法
class Test2<T>
{
public T value;
public void TestFun<K>(K k)
{
Console.WriteLine(k);
}
//这个不叫泛型方法 因为 T是泛型类申明的时候 就指定 在使用这个函数的时候
//我们不能再去动态的变化了
public void TestFun(T t)
{
}
}
5.泛型的作用
//1.不同类型对象的相同逻辑处理就可以选择泛型
//2.使用泛型可以一定程度避免装箱拆箱
//举例:优化ArrayList
class ArrayList<T>
{
private T[] array;
public void Add(T value)
{
}
public void Remove( T value)
{
}
}
6.总结
//1.申明泛型时 它只是一个类型的占位符
//2.泛型真正起作用的时候 是在使用它的时候
//3.泛型占位字母可以有n个用逗号分开
//4.泛型占位字母一般是大写字母
//5.不确定泛型类型时 获取默认值 可以使用default(占位字符)
//6.看到<>包裹的字母 那肯定是泛型
7.练习题
定义一个泛型方法,方法内判断该类型为何类型,并返回类型的名称与占有的字节数
如果是int,则返回“整形,4字节”
只考虑以下类型
int:整形
char:字符
float:单精度浮点数
string:字符串
如果是其它类型,则返回“其它类型”
(可以通过typeof(类型) == typeof(类型)的方式进行类型判断)
static string Fun<T>()
{
if( typeof(T) == typeof(int) )
{
return string.Format("{0},{1}字节", "整形", sizeof(int));
}
else if (typeof(T) == typeof(char))
{
return string.Format("{0},{1}字节", "字符", sizeof(char));
}
else if (typeof(T) == typeof(float))
{
return string.Format("{0},{1}字节", "单精度浮点数", sizeof(float));
}
else if (typeof(T) == typeof(string))
{
return string.Format("{0},{1}字节", "字符串", "?");
}
return "其它类型";
}
泛型约束
1.什么是泛型约束
//让泛型的类型有一定的限制
//关键字:where
//泛型约束一共有6种
//1.值类型 where 泛型字母:struct
//2.引用类型 where 泛型字母:class
//3.存在无参公共构造函数 where 泛型字母:new()
//4.某个类本身或者其派生类 where 泛型字母:类名
//5.某个接口的派生类型 where 泛型字母:接口名
//6.另一个泛型类型本身或者派生类型 where 泛型字母:另一个泛型字母
// where 泛型字母:(约束的类型)
2.各泛型约束讲解
#region 值类型约束
class Test1<T> where T:struct
{
public T value;
public void TestFun<K>(K v) where K:struct
{
}
}
#endregion
#region 引用类型约束
class Test2<T> where T:class
{
public T value;
public void TestFun<K>(K k) where K:class
{
}
}
#endregion
#region 公共无参构造约束
class Test3<T> where T:new()
{
public T value;
public void TestFun<K>(K k) where K : new()
{
}
}
class Test1
{
public Test1()
{
}
}
class Test2
{
public Test2(int a)
{
}
}
#endregion
#region 类约束
class Test4<T> where T : Test1
{
public T value;
public void TestFun<K>(K k) where K : Test1
{
}
}
class Test3:Test1
{
}
#endregion
#region 接口约束
interface IFly
{
}
interface IMove:IFly
{
}
class Test4:IFly
{
}
class Test5<T> where T : IFly
{
public T value;
public void TestFun<K>(K k) where K : IFly
{
}
}
#endregion
#region 另一个泛型约束
class Test6<T,U> where T : U
{
public T value;
public void TestFun<K,V>(K k) where K : V
{
}
}
#endregion
3.约束的组合使用
class Test7<T> where T: class,new()
{
}
4.多个泛型有约束
class Test8<T,K> where T:class,new() where K:struct
{
}
5.总结
//泛型约束:让类型有一定限制
//class
//struct
//new()
//类名
//接口名
//另一个泛型字母
//注意:
//1.可以组合使用
//2.多个泛型约束 用where连接即可
6.练习题
1.练习题1
#region 练习题一
//用泛型实现一个单例模式基类
class SingleBase<T> where T:new()
{
private static T instance = new T();
public static T Instance
{
get
{
return instance;
}
}
}
class GameMgr : SingleBase<GameMgr>
{
public int value = 10;
}
class Test : SingleBase<Test>
{
public int value = 10;
}
class Test2
{
private static Test2 instance = new Test2();
public int value = 10;
private Test2()
{
}
public static Test2 Instance
{
get
{
return instance;
}
}
}
#endregion
2.练习题2
#region 练习题二
//利用泛型知识点,仿造ArrayList实现一个不确定数组类型的类
//实现增删查改方法
class ArrayList<T>
{
private T[] array;
//当前正儿八经存了多少数
private int count;
public ArrayList()
{
count = 0;
//一开始的容量就是16
array = new T[16];
}
public void Add(T value)
{
//是否需要扩容
if( count >= Capacity )
{
//搬家 每次 家扩容2倍
T[] temp = new T[Capacity * 2];
for (int i = 0; i < Capacity; i++)
{
temp[i] = array[i];
}
//重新指向地址
array = temp;
}
//不需要扩容 直接加
array[count] = value;
++count;
}
public void Remove(T value)
{
//这个地方 不是小于数组的容量
//是小于 具体存了几个值
int index = -1;
for (int i = 0; i < Count; i++)
{
//不能用==去判断 因为 不是所有的类型都重载了运算符
if( array[i].Equals(value))
{
index = i;
break;
}
}
//只要不等于-1 就证明找到了 那就去移除
if(index != -1)
{
RemoveAt(index);
}
}
public void RemoveAt(int index)
{
//索引合法不
if( index < 0 || index >= Count )
{
Console.WriteLine("索引不合法");
return;
}
//后面的往前放
for (; index < Count - 1; index++)
{
array[index] = array[index + 1];
}
//把一个数移除了 后面的往前面放 那么最后一个 要移除
array[Count - 1] = default(T);
--count;
}
public T this[int index]
{
get
{
if (index < 0 || index >= Count)
{
Console.WriteLine("索引不合法");
return default(T);
}
return array[index];
}
set
{
if (index < 0 || index >= Count)
{
Console.WriteLine("索引不合法");
return;
}
array[index] = value;
}
}
/// <summary>
/// 获取容量
/// </summary>
public int Capacity
{
get
{
return array.Length;
}
}
/// <summary>
/// 得到具体存了几个值
/// </summary>
public int Count
{
get
{
return count;
}
}
}
#endregion