看到他我一下子就悟了-- 泛型(2)
先说些题外话,只所以写这些东西。是看了CSDN上的曹版主的一篇:手把手教编程,不知道有没有人愿意参与。说实话,我工作四年,总感觉晕晕乎乎的,好多技术都
懂,但是没有一项是精通的。看了这篇帖子,说实在话我可想去,去聆听大神的教导。主要是想提高自己,由于没有时间,又因为身在北京。所以就没有报名(呵呵,报名也
可能没有机会去)。所以自己就去图书馆去搞他提出的这些概念。其实我更希望在北京的大神们也能组织类似的活动。我想响应一定也很多,其实我想如果能组织一次这样的
活动,大神们也会得到提高的。这些都是我在图书馆看书的所得,分享给大家,同时也请管理员同志手下留情,不要每一篇都给打入冷宫,我已经很用心去做了。另外对这
感兴趣的童鞋们可以加我的QQ348537081,我们可以讨论一下心得。最后喜欢看书的童鞋也可以联系我,每周六首都图书馆,风雨无阻。
说的有些多,下面转入正题。其实这篇文章是泛型介绍(接上一篇,具体的事例随后呈上)的扩展与修改。
因为家中无法联网,我都是提前用wps提前写好的,所有格式上可能会有一些问题,所以请大家多担待。
2.2接口约束(where T:interface-name)
为了规定某个数据类型必须实现某个接口,需要声明一个接口约束(interface constraint).有了这种约束之后,甚至不需要执行类型转换,就可以调用一个显示的接口成员实现.接
口约束的主要功能与基类约束完全一样。首先,它允许开发人员在泛型类中使用接口的成员。其次,它确保只能使用实现了特定接口的类型实参。这意味着对于任何给定的接
口约束,类型实参要么是接口本身,要么实现了接口的类。
注:可以通过使用逗号分隔的列表来同时指定多个接口。如果某个约束同时包含基类和接口,则先指定基类再指定接口列表。
如:为了确保T类型参数都是先了IComparable接口,
public class Binary<T> where T:System.IComparable{...}
编译器会确保每次使用Binary类的时候,都必须指定一个实现了IComparable接口的类型参数.
下面的程序通过改写前一个程序中的电话列表程序来说明接口约束的用途。在此程序中,PhoneNumber类被转换为一个名为IPhoneNumber的接口。然后,Friend和Supplier实现了该接口。
class NotFoundException1 : Exception { public NotFoundException1() : base() { } public NotFoundException1(string str) : base(str) { } public NotFoundException1(string str, Exception inner) : base(str, inner) { } protected NotFoundException1(System.Runtime.Serialization.SerializationInfo si, System.Runtime.Serialization.StreamingContext sc) : base(si, sc) { } } public interface IPhoneNumber { public string Number { get; set; } public string Name { get; set; } } public class Friend1 : IPhoneNumber { public string Number { get; set; } public string Name { get; set; } public bool IsWorkNumber { get; set; } public Friend1(string name, string num, bool wk) { Name = name; Number = num; IsWorkNumber = wk; } } public class Supplier1 : IPhoneNumber { public string Name { get; set; } public string Number { get; set; } public Supplier1(string name, string num) { this.Name = name; this.Number = num; } } class FriendEmail1 { } class PhoneList1<T> where T : IPhoneNumber { T[] phList; int end; public PhoneList1() { phList = new T[10]; end = 0; } public bool Add(T newEntry) { if (end == 10) return false; phList[end] = newEntry; end++; return true; } public T FindByName(string name) { foreach (T item in phList) { if (item.Name == name) return item; } throw new NotFoundException1(); } public T FindByNum(string num) { foreach (T item in phList) { if (item.Number == num) return item; } throw new NotFoundException1(); }
2.3 struct/class 约束(where T:class/struct)
另一个重要的泛型约束是将类型参数限制为一个值类型或者一个引用类型.编译器不允许在一个约束中将System.ValueType指定成基类.相反,C#提供了特殊的语法,这种语法同时适用于引用类型.在这种语法中,不是为T指定一个基类.相反,只需要指定关键字struct或者class.在同时存在其他约束时,class或者struct必须位于约束列表的开头
例:
Public struct Nullable<T>:IFormattable,IComparable,IComparable<Nullable<T>>,INullable where T:struct
{//.......}
2.4 new()构造函数约束
New()构造函数约束允许开发人员实例化一个泛型类型的对象。一般情况下,无法创建一个泛型类型参数的实例。然而,new()约束改变了这种情况,它要求类型实参必须
提供一个无参数的构造函数。在使用new()约束的时候,可以通过调用该无参构造函数来创建对象。
class myclass { public myclass() { } } class Test<T> where T : new() { T obj; public Test() { obj = new T(); } }
调用:
Test<myclass> x = new Test<myclass>();
注意:myclass 不必显示地声明一个无参数构造函数,默认的构造函数也可以满足这种约束。然而,如果某个类除了无参的构造函数外还需要定义其他的构造函数,那么必须
为该类显式地声明不含参数的构造函数。
使用new()时,应注意三点:
一、它可以和其他约束一起使用,但必须位于约束列表的末端。
二、New()不允许给类型参数的构造函数传递实参
三、不可以同时使用new()约束和值类型约束
2.5多重约束
同一个参数可以使用多个约束。这种情况下,需要使用一个逗号分隔的约束列表.在该列表中,第一个约束必须是class或者struct(如果存在的话),或者基类(如果被指
定)。指定class或者struct的同时也指定基类约束是非法的。接下来是接口约束。最后是new ()约束。如:
Class Gen<T> where T:myClass,IMyInterface,new(){}
如果有多个类型参数,那么每个类型名称的前面都要使用一个where关键字.如:
Class Gen<T,V> where T:class
Where T:struct
{//.....}
2.6.泛型方法
为了定义泛型方法,需要紧接在方法名之后添加类型参数语法,如
public T method<T>(T params)
{
return params;
}
泛型方法也允许指定约束:
public T method<T>(T params)
where T:IComparable
{
return params;
}
2.7.Default关键字:
要确定用于创建泛型类实例的类型,需要了解一个最基本的情况:他们是引用类型还是值类型.若不知道这个情况,就不能用下面的代码赋予null值:
public class myGenericClass<T1,T2,T3> { T1 t1; public myGenericClass() { t1=null; } }
如果T1是值类型,则t1不能是null,所以这段代码将不会编译.幸好,我们可以用default关键字的新用法解决了它.
public myGenericClass()
{
t1=default(T1);
}
其结果是:如果t1是引用类型,就给它赋予null,如果它是值类型,就赋予默认值.如数字类型,这个默认值就是0.
几个泛型类型的示例:
2.8定义泛型结构
public struct myStruct<T1,T2>
{
public T1 item1;
public T2 item2;
}
2.9定义泛型接口
interface myInterfacee<T>{}
2.10 .定义泛型方法
public T GetDefault<T>()
{
return default(T);
}
2.11定义泛型委托
public delegate T1 myDelegate<T1,T2>(T2 op1,T2 op2) where T1:T2
结束语:泛型到这了,下一次介绍下反射,关于前几篇C#我会抽时间重新写的,能让他更详细点,其实这次C#基础知识的复习让我学到很多东西,以前模糊的概念,
现在变得非常清晰了。我曾经面试过好多人,有工作三年,有两年,甚至工作经验比我还长的。对这些基础性的知识都知之甚少,当然也包括我自己。因为如果没
有这些概念,工作中也不会可虑到这些东西,当然也就谈不上引用。所以我们都只能做底层程序。程序猿想提高,重新学这些基础知识吧,真的……