最近学习了一些C#中关于泛型的知识,总结一下加深记忆。
为什么要使用泛型
在实现类的功能的时侯,有时我们会发现,某些方法的实现过程一样,但操作的对象类型不同,例如交换两个变量的值的Swap方法,将两个变量值相加的方法…如果使用方法重载,会造成大量的代码重复,不利于维护与扩展。
这时你可能会说使用object类型,因为object类型是C#中所有类型的基类,只要将方法的形参设置为object类型,就可以处理不同的类型的数据。例子如下:
class Operation
{
public object DoSomething(object A,object B)
{
... //对A、B进行处理,并用与A、B同类型的值保存结果
return objectC; //返回处理后的值
}
}
//测试
Operation m_operation=new Operation();
int x=5;
int y=6;
int z=m_operation.DoSomething(x,y); //错误,编译器不自动执行object向其他类型的转换
int z=(int)m_operation.DoSomething(x,y); //要显示的进行类型转换
使用object有两个缺点,一是将一个object类型赋给一个具体类型时,需要显示转换,很容易忘记进行显示转换或忘记某个object类型原来是什么类型;二是将一个值类型转换为object类型时需要进行装箱,将object类型转换为一个值类型需要进行拆箱,这使得对于多个值类型的操作带来了巨大的额外开销。
现在我们使用泛型来解决上面的问题
class Operation<TItem>
{
public TItem DoSomething(TItem A,TItem B)
{
... //对A、B进行处理,并用与A、B同类型的值保存结果
return objectC; //返回处理后的值
}
}
//测试
Operation<int> intOperation=new Operation<int>();
int x=5;
int y=6;
int z=intOperation.DoSomething(x,y); //现在就正确了
泛型的约束
有时候为了确保泛型使用的类型必须具备某些操作,可以为作为泛型的类型设定约束,例如,假设我们要定义一个有序地保存数据的泛型类,那么作为该类的类型必须能相互比较大小,例子如下:
public class Example<TItem> where TItem:IComparable
{
...
}
作为TItem的类型必须实现IComparable接口。
泛型方法
还可定义泛型方法,例子如下:
static void Swap<TItem>(TItem A,TItem B)
{
TItem temp=A;
A=B;
B=temp;
}
运用:利用泛型构造二叉树
class Tree<TItem>where TItem:IComparable<TItem> //IComparable是C#中原有的一个接口
{
public TItem node; //该树的根节点
public Tree<TItem> leftTree; //左子树
public Tree<TItem> rightTree; //右子树
public Tree(TItem data) //构造函数
{
this.node=data;
this.leftTree=null;
this.rightTree=null;
}
public void Insert(TItem newNode) //插入节点
{
TItem currentData=this.node;
if(currentData.CompareTo(newNode)>0) //如果当前节点值大于插入节点值
{
if(this.leftTree==null) //左子树为空,则以newNode创建一棵新树
{
this.leftTree=new Tree<TItem>(newNode);
}
else //若左子树不为空,则对左子树进行插入,一直到某棵子树为空时为止
{
this.leftTree.Insert(newNode);
}
}
else //原理同上
{
if(this.rightTree==null)
{
this.rightTree=new Tree<TItem>(newNode);
}
else
{
this.rightTree.Insert(newNode);
}
}
}
public string WalkTree() //遍历该树,并将结果以字符串形式输出出来
{
string result="";
while(this.leftTree!=null)
{
result=this.leftTree.WalkTree();
}
result+=this.node.ToString();
while(this.rightTree!=null)
{
result+=this.rightTree.WalkTree();
}
return result;
}
}