C# 泛型接口
使用泛型可以定义接口,在接口中定义的方法可以带泛型参数。
比如,我们要实现一个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关键字标注,泛型接口就是抗变的。