C# 泛型约束讲解
为什么加约束
当我们用泛型很爽的时候,有人说适当的加上约束比较好。可是为什么呢?
因为泛型是可以任意类型的,此时就有潜在的危险,当我们滥用泛型时就可能搞不清我们的泛型是什么类型的了,所以为了代码的可读性和结构性,我们要给泛型加上约束。
约束关键字
where
举个简单的例子
class test<T>where T:new()
{
}
格式
<泛型字母> where 泛型字母:约束类型关键字
约束类型关键字
- 1.值类型 Struct (整型,浮点型,十进制类型,Bool类型,枚举类型,可谓NULL类型) bool,byte,char,decimal,double,float,int,long…
- 引用类型 Class(对象类型,动态类型,字符串类型)对象类型:类,Object 动态类型:数组,委托,集合array…
- 存在无参公共构造函数 new()
- 某一类本身或者其派生类 泛型字母:类名
- 某一接口其派生类型 泛型字母:接口名
- 另一泛型类型本身或者派生类型 泛型字母:另一个泛型字母
c#数据类型
各各类型实例
值类型约束 struct
class Test1<T> where T:struct
{
public T value;
public T GetT<T>(T v)
{
return v;
}
}
class Program
{
static void Main(string[] args)
{
Test1<int> test1 = new Test1<int>();
test1.value = 10;
Console.WriteLine(test1.GetT(test1.value));
}
}
引用类型约束 class
class Test2<T> where T:class
{
public T value;
public T GetT<T>(T v)
{
return v;
}
}
class Program
{
static void Main(string[] args)
{
Test2<string> test2 = new Test2<string>();
test2.value = "皮学渣真帅";
Console.WriteLine(test2.GetT(test2.value));
}
}
约束类型不匹配的话会报错
int是值类型不是引用类型
无参构造函数 new()
class Test3<T> where T:new()
{
public T value;
}
class Test4
{
public Test4()
{
Console.WriteLine("我是无参构造函数Test4");
}
}
class Program
{
static void Main(string[] args)
{
Test3<Test4> test3 = new Test3<Test4>();
test3.value = new Test4();
}
}
运行结果:
某一类本身或者其派生类 T:类名
class Test4
{
public Test4()
{
Console.WriteLine("我是无参构造函数Test4");
}
}
class Test5:Test4//做一个test4的派生类
{
public Test5()
{
Console.WriteLine("我是Test5的构造函数");
}
}
class Test6<T> where T:Test4
{
public T value;
}
class Program
{
static void Main(string[] args)
{
Test6<Test4> test6 = new Test6<Test4>();
test6.value = new Test4();
test6.value = new Test5();
Test6<Test5> test7 = new Test6<Test5>();
test7.value = new Test5();
}
}
运行结果:
运行结果看不懂的要复习构造函数了…
某一接口其派生类 T:接口名
interface IFly
{
public void fly();
}
interface IRun:IFly
{
public void run();
}
class Test4:IFly
{
public Test4()
{
Console.WriteLine("我是无参构造函数Test4");
}
public void fly()
{
Console.WriteLine("Test4的接口fly");
}
}
class Test5 : Test4
{
public Test5()
{
Console.WriteLine("我是Test5的构造函数");
}
}
class Test7 : IRun
{
public void fly()
{
Console.WriteLine("Test7的接口fly");
}
public void run()
{
Console.WriteLine("Test的接口run");
}
}
class Test8<T> where T:IFly
{
public T value;
}
class Program
{
static void Main(string[] args)
{
Test8<IFly> test8 = new Test8<IFly>();
test8.value = new Test4();
IFly hFly = test8.value;
hFly.fly();//显示转换成接口
test8.value = new Test5();//该代码说明基类继承了约束接口就可以转换。
test8.value = new Test7();//该代码说明就算是接口相互继承,类继承了派生接口也是可以转换的。
}
}
运行结果:
另一泛型类型本身或者派生类型 T:K
interface IFly
{
public void fly();
}
class Test9 : IFly
{
public Test9()
{
Console.WriteLine("我是无参构造函数Test9");
}
public void fly()
{
Console.WriteLine("Test9的接口fly");
}
}
class Test10<T,K> where T:K
{
public T value;
}
class Program
{
static void Main(string[] args)
{
Test10<Test9, IFly> test10 = new Test10<Test9, IFly>();
test10.value = new Test9();
test10.value.fly();
}
}
运行结果:
这一个约束可以看成第一个约束字母继承第二个约束第二个约束字母的,或者是第一个字母本身。
两个约束一样
class Program
{
static void Main(string[] args)
{
Test10<Test9, Test9> test10 = new Test10<Test9, Test9>();
test10.value = new Test9();
test10.value.fly();
}
}
运行结果
字母多重约束
单一字母多重约束
class Test<T> where T:class,new()
{
}
这样的话根据上述六个约束类型可以相互组合,但是并不是任意两种就可以组合的。
组合的时候一样要注意顺序和组合类型
不可组合类型例子
顺序组合错误
多个字母多重约束
class Test<T,K> where T:class,new() where K:class,new()
{
}
第一个字母约束设置好后直接跟下一个字母进行约束,中间不加符号