【轉】編寫高質量代碼改善C#程序的157個建議——建議42:使用泛型參數兼容泛型接口的不可變性
阿新 • • 發佈:2017-12-01
-c out bsp counter nag oid 需求 turn ring
建議42:使用泛型參數兼容泛型接口的不可變性
讓返回值類型返回比聲明的類型派生程度更大的類型,就是“協變”。如:
public Employee GetAEmployee(string name) { Console.WriteLine("我是雇員:"+name); return new Programmer() { Name = name };//Programmer是Employee的子類 }
Programmer是Employee的子類,所以Programmer對象也是Employee對象。方法GetAEmployee返回一個Programmer的對象,也就是相當於返回一個Employee對象。
由於協變是一種如此自然的應用,我們很可能寫出如下代碼:
class Program { static void Main(string[] args) { ISalary<Programmer> s = new BaseSalaryCounter<Programmer>(); PrintSalary(s); } static void PrintSalary(ISalary<Employee> s)
{
s.Pay();
} }interface ISalary<T> { void Pay(); } class BaseSalaryCounter<T> : ISalary<T> { public void Pay() { Console.WriteLine("Pay base salary"); } } class Employee { public string Name { get; set; } }class Programmer : Employee { } class Manager : Employee { }
在PrintSalary這個方法中,方法接收的類型是ISalary<Employee>。於是,我們想當然的認為ISalary<Programmer>必然也可以被PrintSalary方法接收的。事實卻不然,代碼編譯會通不過:
無法從“MyTest.ISalary<MyTest.Programmer>”轉換為“MyTest.ISalary<MyTest.Employee>”
編譯器對於接口和委托類型參數的檢查是非常嚴格的,除非用關鍵字out特別聲明,不然這段代碼只會編譯失敗。要讓PrintSalary完成需求,我們可以使用泛型類型參數:
static void PrintSalary<T>(ISalary<T> s) { s.Pay(); }
註意:建議開頭指出“協變”是針對返回值而言的,但是所舉的這個例子並沒有體現“返回值”這個概念。實際上,只有泛型類型參數在一個接口聲明中不被用來作為方法的輸入參數,我們就姑且把它看成是“返回值”類型的。所以,本建議中這種模式是滿足“協變”定義的。但是,只要將T作為輸入參數,就不滿足“協變”定義了。
轉自:《編寫高質量代碼改善C#程序的157個建議》陸敏技
【轉】編寫高質量代碼改善C#程序的157個建議——建議42:使用泛型參數兼容泛型接口的不可變性