您的位置:首页 > 编程语言 > C#

C# 泛型

2016-05-10 20:52 459 查看
泛型:通过参数化类型来实现在同一份代码上操作多种数据类型。利用“参数化类型”将类型抽象化,从而实现灵活的复用。

1、C#的泛型能力由CLR在运行时支持,它既不同于C++在编译时所支持的静态模板,也不同于Java在编译器层面使用“擦拭法”支持的简单的泛型。

2、C#的泛型支持包括类、结构、接口、委托四种泛型类型,以及方法成员。

3、C#的泛型采用“基类,接口,构造器,值类型/引用类型”的约束方式来实现对类型参数的“显式约束”,它不支持C++模板那样的基于签名的隐式约束。

class Program

{
static void Main(string[] args)

{
int obj = 2;
Test<int> test = new Test<int>(obj);
Console.WriteLine("int:" + test.obj);
string obj2 = "hello world";
Test<string> test1 = new Test<string>(obj2);
Console.WriteLine("String:" + test1.obj);
Console.Read();
}
}
class Test<T>
{
public T obj;
public Test(T obj)
{
this.obj = obj;
}
}


输出结果是:

int:2

String:hello world

1、 Test是一个泛型类。T是要实例化的范型类型。如果T被实例化为int型,那么成员变量obj就是int型的,如果T被实例化为string型,那么obj就是string类型的。

2、 根据不同的类型,上面的程序显示出不同的值。

系统提供了许多泛型类和泛型接口,List<T>和Dictionary<K,V>是常用的泛型类。IComparable<T>是最常用的泛型接口。泛型接口具有一般接口的共同特点,即在接口中可以包含字段,属性,方法和索引器,但都不能实现。

使用泛型可以定义接口,在接口中定义的方法可以带泛型参数。

比如,我们要实现一个IComparable接口来对两个类的对象的属性进行比较。传统的我们会这么做:

public class Person : IComparable
{
public string LastName { get; set; }
public Person(string lastName) { this.LastName = lastName; }

public int CompareTo(object obj)
{
Person other = obj as Person; //这里需要做强制转换,然后才能对属性进行比较
return this.LastName.CompareTo(other.LastName);
}
}


我们看一下引入泛型接口之后,会发生什么变化:

同样的我们还是要实现IComparable接口,不同的是这是一个泛型接口

public class Person : IComparable<Person>
{
public string LastName { get; set; }

public Person(string lastName) { this.LastName = lastName; }

public int CompareTo(Person other)
{
return this.LastName.CompareTo(other.LastName);//这里可以直接对属性进行操作,不需要之前的转换过程了
}
}


然后就可以在main函数中测试一下上面的代码:

static void Main(string[] args)
{
Person[] person = new Person[] { new Person("Microsoft"), new Person("google") };
int result = person[0].LastName.CompareTo(person[1].LastName);
Console.WriteLine(result);//输出1
}


上述的例子说明了一点,泛型接口就是带泛型类型的接口,与普通的接口相比,多了类型的约束。.NET1.0就有了基于对象的IComparable接口,IComparable<in T>基于一个泛型类型:

public interface IComparable<in T>
{
int CompareTo(T other);
}


接下来,讲两个与泛型接口有关的两个概念:协变和抗变。

先定义一个基类Shape:

public class Shape
{
public double Width { get; set; }
public double Height { get; set; }

public override string ToString()
{
return string.Format("width:{0},height:{1}", Width, Height);
}
}


再定义一个泛型接口:泛型类型用out关键字标注,表明泛型接口是协变的(也就是说返回类型只能是T),并从一个只读索引器中返回这个类型。

public interface IDisPlay<out T>
{
T this[int index] { get; }
}


接下来定义一个Rectangle子类继承Shape类,并实现泛型接口IDisPlay(out T)。

public class Rectangle : Shape, IDisPlay<Shape>
{
Shape IDisPlay<Shape>.this[int index]
{
get
{
if (index != 0)
{
throw new ArgumentOutOfRangeException("index");
}
else
{
this.Width = 400;
this.Height = 500;
return this;
}
}
}
}


最后我们测试一下结果:

static void Main(string[] args)
{
IDisPlay<Shape> shapeDisplay = new Rectangle();//把实现了泛型接口的类对象赋值给泛型接口
Console.WriteLine(shapeDisplay[0].ToString());//通过泛型接口的索引器访问,返回这个对象
}


确实输出了我们想要的结果:width:400,height:500.

如果泛型类型用in关键字标注,泛型接口就是抗变的。

public interface IList<T>
{
T[] GetElements();
}
public interface IDictionary<K, V>
{
void Add(K key, V value);
}
//泛型接口的类型参数要么已实例化,要么来源于实现类声明的类型参数
class List<T> : IList<T>, IDictionary<int, T>
{
public T[] GetElements()
{
return;
}
public void Add(int index, T value)
{

}

}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: