作业2
泛型
1.泛型的定义
publicclassMyClass{// 泛型方法:单独的方法也可以设置成泛型publicvoidMyClassMethod2<T>(Ta){Console.WriteLine(a);// 获取传入参数的实际类型Console.WriteLine(a.GetType().ToString());}// 方法也支持多个泛型类型参数publicvoidMyClassMethod3<T,U,K>(Ta,Ub,Kc){Console.WriteLine(a.GetType().ToString());Console.WriteLine(b.GetType().ToString());Console.WriteLine(c.GetType().ToString());}// 泛型类型参数别名可以使用中文(不推荐用于生产环境)publicvoidMyClassMethod4<人,车,动物>(人 a,车 b,动物 c){Console.WriteLine(a.GetType().ToString());Console.WriteLine(b.GetType().ToString());Console.WriteLine(c.GetType().ToString());}}用类型参数代替具体类型,实现代码复用
2.泛型接口
// 定义一个泛型接口publicinterfaceIInterface<T>{Ttest1{get;set;}stringtest2{get;set;}TMethod();voidMethod1(Tabc);}// 泛型接口可以继承另一个泛型接口,并选择指定具体类型或保持泛型// 方式一:指定具体类型(如 string)publicinterfaceIIInterface<D>:IInterface<string>{DBoo{get;set;}voidSetBoo(Dvalue);}// 实现 IIInterface<int>publicclassMyClass2:IIInterface<int>{publicintBoo{get;set;}publicstringtest1{get;set;}publicstringtest2{get;set;}publicstringMethod(){returntest1;}publicvoidMethod1(stringabc){Console.WriteLine(abc);}publicvoidSetBoo(intvalue){Console.WriteLine(value);}}// 方式二:保持泛型,让实现类决定具体类型publicinterfaceIAnotherInterface<T,D>:IInterface<T>{DExtraData{get;set;}}// 实现 IAnotherInterface<string, int>publicclassMyClass3:IAnotherInterface<string,int>{publicstringtest1{get;set;}publicstringtest2{get;set;}publicintExtraData{get;set;}publicstringMethod(){returntest1;}publicvoidMethod1(stringabc){Console.WriteLine(abc);}}// 直接实现泛型接口,指定具体类型publicclassMyClass4:IInterface<int>{publicinttest1{get;set;}publicstringtest2{get;set;}publicintMethod(){returntest1;}publicvoidMethod1(intabc){Console.WriteLine(abc);}}3.泛型的约束
// 基类publicclassBaseEntity{publicintId{get;set;}}// 接口publicinterfaceIAuditable{voidLogAction(stringaction);}// 同时继承基类和实现接口的类publicclassUser:BaseEntity,IAuditable{publicstringName{get;set;}publicvoidLogAction(stringaction){Console.WriteLine($"Audit --{Name}:{action}");}}// 泛型约束类// 约束顺序:基类(最多一个) -> 接口(零个或多个) -> new()(必须放在最后)publicclassRepository<T>whereT:BaseEntity,IAuditable,new(){privateList<T>_items=newList<T>();publicvoidAdd(){// 因为 new() 约束,可以安全地实例化 TTitem=newT();Console.WriteLine($"创建了一个{typeof(T).Name}对象");_items.Add(item);// 将新对象加入内部列表}publicvoidSave(Tentity){// 由于 BaseEntity 约束,可以直接访问 Id 属性Console.WriteLine($"保存了 entity 的类型:{entity.GetType().Name}, Id:{entity.Id}");entity.LogAction("Save 操作");_items.Add(entity);}publicList<T>GetAll(){return_items;}}//U是T的约束条件,所以T一定是U的子类型// 类型参数之间的约束:T 必须能隐式转换为 UpublicclassWrapper<T,U>whereT:U{publicTItem;publicUSetUUU(Ta,Ub){returnb;}}T : U 的含义:T 必须能够隐式转换为 U。
如果 U 是类,T 必须是 U 或其派生类。
如果 U 是接口,T 必须实现该接口。
如果 U 是另一个类型参数,则 T 必须满足该参数所代表的类型约束。
4.泛型的默认值
publicclassTestDefault<T>{// 使用 default 关键字获取各类型的默认值intdefaultInt=default;// 0booldefaultBool=default;// falsestringdefaultString=default;// nullpublicvoidTestValue(){Console.WriteLine($"int 的默认值是:{defaultInt}");// 0Console.WriteLine($"bool 的默认值是:{defaultBool}");// falseConsole.WriteLine($"string 的默认值是:{defaultString}");// null}// 返回泛型 T 的默认值// 对于值类型(如 int)返回 0,对于引用类型(如 string)返回 nullpublicTGetDefaultValue(){returndefault(T);}// 如果列表不为空,返回最后一个元素;否则返回默认值publicTGetLastItem(List<T>items){if(items==null||items.Count==0){returndefault(T);}else{returnitems[items.Count-1];}}}| 知识点 | 说明 |
|---|---|
| 泛型方法 | 可以在非泛型类中定义,类型参数由调用时传入的参数推断 |
| 泛型接口继承 | 继承时可指定具体类型,也可保持泛型让子类决定 |
| 泛型约束 | where T : 基类, 接口1, 接口2, new()顺序固定 |
default(T) | 值类型返回0/false,引用类型返回null,避免NullReferenceException |