2012-04-11 134 views
3

我注意到其他開發者使用這種技術,但它總是困惑我。我決定今天上午進行調查,並遇到下列來到MSDN(從http://msdn.microsoft.com/en-us/library/d5x73970(v=vs.100).aspx):類型參數約束是一個類

public class GenericList<T> where T : Employee 
{ 
... 
} 

我們爲什麼要改用的類員工替換T的實例的這種方法嗎?對我來說,這似乎是一個可維護性的勝利。我可以理解,將接口限制爲包含來自不同繼承層次的類的方法,但繼承已經以更明顯的方式解決了上述問題,不是嗎?

這可能被認爲是一個錯誤,或者這會是一個錯誤'修復'這樣的代碼?

+0

雖然這現在對我來說很有意義,我想我還是看到了這個方法當非通用方法更合適時可能會出現這種情況,這可能會使我的視野模糊到更爲可接受的用途。 – Sprague 2012-04-11 08:28:07

+0

@sprague:你能舉個例子嗎?最好從lib? – 2012-04-11 08:44:41

+0

@亨克霍爾特曼:可以說,會有類型參數是多餘的情況。這是一個例子,我最感興趣的是一個具有特定類的約束的類型參數的有效情況。我不想對這種情況做出判斷,直到我理解了這種情況(這一點,感謝你和其他人,我現在這樣做)。 – Sprague 2012-04-11 10:04:49

回答

7

因爲它可能是派生自Employee的東西。

public class EvilEmployee : Employee { 
    public Int32 Evilness { get; set; } 
} 

它現在可以做到......

GenericList<EvilEmployee> list = GetEvilEmployees(); 
var mostEvilEmployee = list.OrderByDescending(e => e.Evilness).First(); 

這是可能的,因爲我們知道,在編譯時,即T = EvilEmployee和EvilEmployee有一個邪惡屬性。如果我們強制將列表強制爲無法使用的Employee列表(不使用OfType)。

+0

爲了擴大:如果一個具有類受限的泛型類型T的類沒有返回任何類型爲T或T的類型的方法,沒有類型爲T或T的類型的參考/輸出參數,並且不接受任何類型的消費者T或涉及T的類型,那麼通常可以用約束類型替換T類型的所有事件。類本身並不介意將約束類型替換爲泛型,但是如果它具有任何提及的返回或參數類型,那麼想要使用具有派生類型的類的代碼將會遇到問題。 – supercat 2012-04-11 23:34:36

5

爲什麼我們要使用這種方法而不是用類中的Employee替換T的所有實例?

要啓用:

class Manager : Employee { ... } 

var board = new GenericList<Manager>(); 

需要注意的是你的名字GenericList「會在這種情況下更喜歡「EmployeeList的」

我能理解限制到一個接口的一種手段包括來自不同繼承層次結構的類

類繼承和接口有很多共同之處。

但是繼承已經以更爲明顯的方式解決了上述問題,不是嗎?

是的,但它不一樣。 board.Add(lowlyProgrammer);將在這裏失敗,而繼承將允許它。

+0

經理已經是一名僱員,這已經可能具有多態性...我錯過了什麼嗎? – Sprague 2012-04-11 08:19:41

+0

@Sprague:'board.Add(lowlyProgrammer);'會在這裏失敗。 – 2012-04-11 08:20:29

+1

+1簡潔 - 一種在泛型上強制執行類型層次安全性的簡單方法,同時也保持與「T」類型相同的輸入/輸出類型(例如添加/獲取方法);如果它是非通用的,則簡化調用方的使用。 – 2012-04-11 08:20:31

0

哪裏陳述是有意添加的。考慮一下從Employee類派生類的情況;如果您沒有定義泛型類,則需要爲每個派生類定義一個類。

例如,如果EmployeeX繼承Employee,並且想要定義一個只接受EmployeeX實例的List,那麼通過使用泛型方法,您不需要定義一個新類。

0

泛型允許您在不需要投射的情況下進行類型保護。

,如果你有

public class Manager : Employee 
    { 
    public double CalculateManagerBonus(); 
    } 

你可以做

GenericList<Manager> managers = .... 

    managers[0].CalculateManagerBonus(); 

,如果你有

GenericList<Employee> managers = .... 

    // this is a compiler error 
    managers[0].CalculateManagerBonus(); 

    // this is neccessary if there where no generics. 
    ((Manager)managers[0]).CalculateManagerBonus();