一、概念
泛型实现了类型参数化,达到代码复用的目的
通过类型参数化来实现同一份代码上操作多种类型
泛型相当于类型占位符
定义类或方法时使用替代符代表变量类型
当真正使用类或者方法时再具体指定类型
泛型的本质是类型参数化或参数化类型,在不创建新的类型的情况下,通过泛型指定的不同类型来控制形参具体限制的类型。
也就是说在泛型使用过程中,操作的数据类型被指定为一个参数,这种参数类型可以用在类、接口和方法中,分别被称为泛型类、泛型接口、泛型方法。
二、泛型类和泛型接口
1.泛型类声明
calss 类名<泛型占位字母>
class TestClass<T>//泛型类
{
public T value;
}
TestClass<int> t1 = new TestClass<int>();
TestClass<string> t2 = new TestClass<string>();
class TestClass2<T1,T2,T3,T4>//泛型类多个参数
{
public T1 value1;
public T2 value2;
public T3 value3;
public T4 value4;
}
TestClass2<int,string,bool,float> t3= newTestClass2<int,string,bool,float>()
2.泛型接口声明
interface 接口名<泛型站位字母>
interface TestInterface<T>//泛型接口
{
T VAlue
{
get;
set;
}
}
class Test:TestInterface<int>
{
//继承时也需填写
}
三、泛型方法
声明
函数名<泛型占位字母>(参数列表)
注意:泛型占位字母可以有多个,用逗号分开
普通类中的泛型方法
Class Test{
public H Test<H>( H v)
{
return v ;//H为 可变类型 使用时指定类型
}
public void Test<T>()
{
T t =default(T);//默认值,可做逻辑处理
}
public void Test<T1,T2,T3>(T1 t1,T2 t2,T3 t3)
{
//可做多个泛型占位符
}
}
2.泛型类中的泛型方法
class Test<T>
{
//T类型的成员变量 当使用该类时 value的类型才被确定
//声明泛型时T也可以换成任何字母(一般用大写)
public T value;
//不是泛型方法
//使用泛型类中的可变类型 作为参数和返回值的
public T Test(T t)
{
return t;
}
//泛型方法 K为可变类型使用时为指定类型
public K Test<K>( K v)
{
return v;
}
}
四、泛型约束
1.概念
限制泛型的类型
关键字:where
2.泛型约束类型
泛型约束一共有6种
where 泛型字母:约束类型
值类型 where 泛型字母:struct
引用类型 where 泛型字母:class
存在无参公共构造函数 where 泛型字母:new()
某个类本身或其派生类 where 泛型字母:类名
某个接口的派生类型 where 泛型字母:接口名
另一个泛型类型本身或者派生类型 where 泛型字母:另一个泛型字母
值类型约束
public class Test<T> where T: struct
{
public T value;
//泛型方法加上值约束代表K只能使用值类型
public void TestFun<K>() where K: struct
{
}
}
//使用时只能使用值类型
Test<int> t = new Test<int>();
t.value = 100;
t.TestFun<float>();
引用类型约束
public class Test<T> where T: class
{
public T value;
//泛型方法加上值约束代表K只能使用引用类型
public void TestFun<K>() where K: class
{
}
}
//使用时 只能使用引用类型
Test<string> t = new Test<string>();
t.value = "123";
t.TestFun<string>();
公共无参构造约束
public class Test<T> where T: new()
{
public T value;
//泛型方法 加上无参约束 代表K类型必须存在无参构造
public void TestFun<K>() where K:new()
{
}
}
public class Test1
{
}
public class Test2
{
public Test2(int a)
{
}
}
//使用时 只能使用含有 无参构造函数的类型
Test<Test1> t = new Test<Test1>();
t.TestFun<Test1>();
类约束
public class Test<T> where T:Test1
{
public T value;
//泛型方法 加上某个类名作为约束 代表K类型必须为该类或者其派生类
public void TestFun<K>() where K:Test1
{
}
}
public class Test1...
public class Test2 : Test1
{
}
public class Test3...
//使用时 只能使用该类或其派生类
Test<Test1> t = new Test<Test1>();
t.TestFun<Test2>();
5.接口约束
public class Test<T> where T : ITest
{
public T value;
//泛型方法 加上某个接口名作为约束 代表T类型必须该接口或者其派生类型
public void TestFun<K>() where K : ITest
{
}
}
public interface Itest...
//继承接口的类
public class Test1 : ITest
{
}
//继承接口的接口
public interface ITest2:Itest
{
}
//没有继承接口
public class Test2...
//使用时 只能使用改接口或者该接口的派生类型
Test<Test1> tt = new Test<Test1>();
t.TestFun<ITest2>();
6.另一个类型约束
public class Test<T,U> where T : U
public T value;
//泛型方法 加上另一个泛型占位符作为约束 K表示必须和L是同一类型或者其派生类型
public void TestFun<K,L>() where K : L
{
}
}
public interface ITest...
//继承接口的类
public class Test1: ITest
{
}
public class Test2...
//使用时 只能使用改接口或者其派生类型
Test<Test1,ITest> t = new Test<Test1,Itest>();
t.TestFun<Test1,Test1>();
3.约束的组合使用
泛型类 多个约束组合使用,用逗号分割 如果不能组合使用会报错
public class Test<T> where T: class , new()
{
public T value;
//泛型方法多个约束组合使用用逗号分隔如果不能组合使用会报错l
public void TestFun<K>( ) where K: ITest, new()
{
}
}
public interface ITest...
4.多个泛型有约束
public class Test<T,H> where T:class,new( ) where H:struct
{
public T value;
//泛型方法多个泛型都有约束用多个where拼接
public void TestFun<K,L>() where K: ITest,new( ) where L:class
{
}
}
public interface ITest. . .
注意:
//当使用泛型作为函数返回值时
public K TestFun<K>()
{
//当没有约束时不确定泛型类型时值还是引用
//可以使用default关键字得到泛型类型作为对象时的默认值返回
//—般情况下 引用为null 值为0
return default(K);
}
五、泛型作用
1.不同类型对象的相同逻辑处理可以选择泛型
2.使用泛型可以一定程度避免装箱拆箱
举例:优化ArrayList
class ArrayList<T>
{
private T[] array;
//增删查改
public void Add(T value)
{
}
}
六、总结
1.泛型类接口方法
声明语法
泛型类
class 类名<占位字母>
泛型接口
interface 接口名<泛型站位字母>
泛型方法
返回值类型 函数名<占位字母>(参数类型 参数...)
概念
泛型相当于类型占位符
占位字母可以有多个
占位字母一般为大写字母
定义类或方法时使用替代符代表变量类型
当真正使用类或者方法时再具体指定类型
2.泛型约束
约束语法
关键词:where
值类型
where T:struct
引用类型
where T:class
必须存在无参公共构造函数
where T:new()
某个类的派生类
where T:类名
某个接口的派生类型
where T:接口名
另一个泛型的派生类型
where T:U
作用
使用泛型指定类型时
有一定的规则
注意
部分约束可以组合使用
多个约束用逗号隔开
多个泛型都有约束
用多个where
补充
泛型对象默认值
default(泛型占位符)