使用泛型可以定義介面,在介面中定義的方法可以帶泛型參數。
比如,我們要實現一個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關鍵字標註,泛型介面就是抗變的。