泛型的几个值得留意的应用点
☆ default 关键字
在泛型类和泛型方法中产生的一个问题是,在预先未知以下情况时,如何将默认值分配给参数化类型 T:
(a) T 是引用类型还是值类型。
(b) 如果 T 为值类型,则它是数值还是结构。
给定参数化类型 T 的一个变量 t,只有当 T 为引用类型时,语句 t = null 才有效;只有当 T 为数值类型而不是结构时,语句 t = 0 才能正常使用。解决方案是使用 default 关键字,此关键字对于引用类型会返回空,对于数值类型会返回零。对于结构,此关键字将返回初始化为零或空的每个结构成员,具体取决于这些结构是值类型还是引用类型。以下来自 GenericList<T> 类的示例显示了如何使用 default 关键字。
☆ 实参推断:
当不指定类型实参调用泛型方法时,类型推断 (type inference) 过程将尝试为该调用推断类型实参,支持所有类型参数(包括自定义类型)。
![](https://images.cnblogs.com/OutliningIndicators/ContractedBlock.gif)
public class HerClass
{
public string v = "value";
public HerClass(string v){this.v = v;}
}
public struct MyStruct
{
public int count;
}
public class YourClass
{
public YourClass(){ }
public static T ICanConcludeYourType<T>(T t){return t;}
}
public class GenericsClass<T>
{
public string ss = "ss";
public GenericsClass(string s) { this.ss = s; }
}
public class Main
{
// 推断参数类型,以下调用均能达到预期值
public static void CallFunction()
{
// 对值类型
object s = YourClass.ICanConcludeYourType<string>("ok");
object s1 = YourClass.ICanConcludeYourType("ok too");
MyStruct ms = new MyStruct();
ms.count = 1;
object t = YourClass.ICanConcludeYourType<MyStruct>(ms);
object t1 = YourClass.ICanConcludeYourType(ms);
// 对引用类型
HerClass hc = new HerClass("ok for HerClass");
object s2 = YourClass.ICanConcludeYourType<HerClass>(hc);
object s3 = YourClass.ICanConcludeYourType(hc);
GenericsClass<MyStruct> msg = new GenericsClass<MyStruct>("generics");
object t2 = YourClass.ICanConcludeYourType<GenericsClass<MyStruct>>(msg);
object t3 = YourClass.ICanConcludeYourType(msg);
}
}
{
public string v = "value";
public HerClass(string v){this.v = v;}
}
public struct MyStruct
{
public int count;
}
public class YourClass
{
public YourClass(){ }
public static T ICanConcludeYourType<T>(T t){return t;}
}
public class GenericsClass<T>
{
public string ss = "ss";
public GenericsClass(string s) { this.ss = s; }
}
public class Main
{
// 推断参数类型,以下调用均能达到预期值
public static void CallFunction()
{
// 对值类型
object s = YourClass.ICanConcludeYourType<string>("ok");
object s1 = YourClass.ICanConcludeYourType("ok too");
MyStruct ms = new MyStruct();
ms.count = 1;
object t = YourClass.ICanConcludeYourType<MyStruct>(ms);
object t1 = YourClass.ICanConcludeYourType(ms);
// 对引用类型
HerClass hc = new HerClass("ok for HerClass");
object s2 = YourClass.ICanConcludeYourType<HerClass>(hc);
object s3 = YourClass.ICanConcludeYourType(hc);
GenericsClass<MyStruct> msg = new GenericsClass<MyStruct>("generics");
object t2 = YourClass.ICanConcludeYourType<GenericsClass<MyStruct>>(msg);
object t3 = YourClass.ICanConcludeYourType(msg);
}
}
☆ 几个值得留意的约束
![](https://images.cnblogs.com/OutliningIndicators/ContractedBlock.gif)
class GTypeClass1<T, U>
where T: struct // T 必须是值类型
where U: class // U 必须是引用类型,如类、接口、委托或数组
{
}
class GTypeClass2<T>
where T: new() // T必须拥有一个无参数缺省构造方法。C# 暂时不支持非缺省构造约束。
{}
class GTypeClass3<T>
where T: class, new() // 当T有多个约束时,new()要放在最后。
{}
where T: struct // T 必须是值类型
where U: class // U 必须是引用类型,如类、接口、委托或数组
{
}
class GTypeClass2<T>
where T: new() // T必须拥有一个无参数缺省构造方法。C# 暂时不支持非缺省构造约束。
{}
class GTypeClass3<T>
where T: class, new() // 当T有多个约束时,new()要放在最后。
{}
☆ 运算符
is 运算符支持开放类型。在 e is T 形式的运算中,如果 e 或 T 的编译时类型为开放类型,则始终对 e 和 T 的运行时类型执行动态类型检查。
as 运算符:只有当 T 已知为引用类型时,as 运算符才可在右侧用于类型参数 T。需要这个限制是因为值 null 可能作为该运算符的结果返回。