定義一個介面和繼承該介面的兩個類別
internal interface IAnimal { string Name { get; set; } int Age { get; set; } } internal class Dog : IAnimal { public string Name { get; set; } public int Age { get; set; } public string Size { get; set; } } internal class Bird : IAnimal { public string Name { get; set; } public int Age { get; set; } public bool IsFlying { get; set; } }
實例化兩個List<T>物件
List<Dog> dogs = new List<Dog> { new Dog{Name="Dog 1",Age=3, Size="Small"}, new Dog{Name="Dog 2",Age=5, Size="Big"} }; List<Bird> birds = new List<Bird> { new Bird{Name="Bird 1",Age=4,IsFlying=true}, new Bird{Name="Bird 2",Age=2,IsFlying=false} };
演示 IEnumerable<out T>協變介面
1.
建立一個 List<IAnimal>, 並調用 AddRange 向其添加 Dog 和 Bird列表(List);List<IAnimal> animals = new List<IAnimal>(); animals.AddRange(dogs); animals.AddRange(birds);
List<T>.AddRange 的參數為 IEnumerable<T> 類型,
因此這種情況下,將這兩個列表都看成是 IEnumerable<IAnimal>,而這以前是不允許的。
2.
使用LINQ方法,根據已知序列的數據創建列表;List<IAnimal> concat = dogs.Concat<IAnimal>(birds).ToList();
不能直接調用 dogs.Concat(birds),這會使類型推斷機制變得混亂, 應該顯示地指定類型參數。
dogs 和 cats 都將根據協變性而隱式轉換為 IEnumerable<IAnimal>, 這種轉換不會真正改變它們的值,所改變的只是編譯器如何看待這些值。
結果:
foreach (var item in animals) { Console.WriteLine(item.Name); }顯示 :
Dog 1
Dog 2
Bird 1
Bird 2
無法使用 item.Size 或是 item.IsFlying, 除非轉為 Dog 或是 Bird:
foreach (var item in animal) { if (item is Bird) { var bird = (Bird)item; Console.WriteLine("the bird is flying? {0}", bird.IsFlying); } }
演示 IComparer<in T> 逆變介面
internal class AgeComparer : IComparer<IAnimal> { public int Compare(IAnimal x, IAnimal y) { return x.Age.CompareTo(y.Age); } }自定 AgeComparer 類別,實現 IComparer<T>
....
IComparer<IAnimal> ageComparer = new AgeComparer(); dogs.Sort(ageComparer);使用逆變性,進行排序;有了 IComparer<IAnimal>,就可以用她進行排序,dogs.Sort 的參數應該為 IComparer<Dog> 類型,但逆變性會進行隱式轉換。
沒有留言:
張貼留言