2011-06-01 72 views
4

我看到的在下面的用法:參數列表中的修飾符的含義是什麼?

Covariance and contravariance real world example

interface IGobbler<in T> { 
    void gobble(T t); 
} 

我不明白的代表使用。是否與編號,

+1

您是否搜索過?如果搜索引擎不採用「in」這個詞,你可能需要使用'+ in'而不是'in'。 – BoltClock 2011-06-01 15:28:26

+0

ref在這方面不適用 – Jodrell 2011-06-01 15:28:41

+0

@BoltClock,我通過使用'C#parameter ref in'或'C#in parameter'搜索谷歌並且沒有有用的信息被返回。 – q0987 2011-06-01 15:42:00

回答

3

忽略你對refout的瞭解,因爲它與此上下文無關。在這種情況下,in意味着T只會出現在函數名稱的右側(即在形式參數列表中,如void gobble(T t))。如果它說out,那麼T只會出現在函數名的左側(即返回值如T foo(int x))。默認(不指定任何內容)允許T出現在任何地方。

+0

爲便於使用術語。像這個答案一樣。 – JonH 2011-06-01 15:40:57

+0

對我來說,這個'out'與我在方法參數列表中知道out參數不同。這意味着您的方法必須在函數返回之前爲該變量賦值。 – q0987 2011-06-01 15:50:09

+0

@ q0987:是的,這是在不同的上下文中使用'out'。在這種情況下,它出現在函數的形式參數列表中。在這種情況下,它出現在界面的類型參數列表中。 – Gabe 2011-06-01 15:53:13

5

4.0中的inout修飾符對強制執行(或者說:啓用)協方差和逆變是必需的。

如果添加in,您只能在向內(逆變)位置使用T - 所以像Add(T obj)是好的,但T this[int index] {get;}因爲這是一個向外(協)的位置。

這對於4.0中的方差特徵很重要。有差異的話,refout都不可用(它們都是,都是這樣:都不)。

+0

您的進出口說明很容易理解。但我仍然無法連接T和接口IGobbler 。根據我的理解,將方法分配給委託時會使用協方差和逆變。正如Eric在他的文章中指出的那樣,它們只是預測。另外,當我們定義一個委託時,我們是否只指定了內部和外部? – q0987 2011-06-01 18:22:50

+0

@ q0987不,這是不正確的;代表***或接口***。最值得注意的是,它現在是'IEnumerable ' – 2011-06-01 18:29:44

+0

在'IGobbler '的情況下,這將強制在該接口上進行反轉。它不會讓你添加一個「向外」的API(一種獲得'T'的方法),因爲這會破壞這個規則。但它也將允許隱含的逆轉演員,這是可愛的。差異完全是可選的。 – 2011-06-01 18:32:40

2

in修飾符告訴你的類型是逆變並可以隱式轉換爲窄型。在下面的例子中注意到,儘管狼吞虎嚥需要Shape,但它可以被分配到Action<Rectangle>,因爲我們已經聲明它是逆變的。這是因爲任何調用委託並將其傳遞給Rectangle的人都可以將Rectangle傳遞給一個也需要Shape的方法。

當您使用inout時,有一些規則,但是這就是它簡單介紹的內容。

例如:

public class Shape { } 

public class Rectangle : Shape { } 

public interface IGobbler<Shape> 
{ 
    void gobble(Shape shape); 
} 

public class Gobbler : IGobbler<Shape> 
{ 
    public void gobble(Shape r)  { }  
} 

public static class Program 
{ 
    public static void Main() 
    { 
     var g = new Gobbler(); 

     // notice can implictly convert to a narrower type because of the 'in' keyword 
     Action<Rectangle> r = g.gobble;  
    } 
} 
+0

我必須缺少一些東西。我在代碼中的任何地方都看不到(僅在評論中)。 – comecme 2011-06-01 16:09:39

+0

@comecme,我假設詹姆斯只是簡單地使用現有的接口IGobbler q0987 2011-06-01 18:25:10

+0

如果我錯了,請糾正我。當分配動作 r = g.gobble時,發生反轉。將Rectangle傳遞給g.gobble時,會發生協方差。那是對的嗎? – q0987 2011-06-01 18:28:10

0

IN關鍵字告訴我們只希望使用T作爲輸入值的編譯器。

它不會允許來自比方說,IGobbler鑄造IGobbler

1

我喜歡把它看作是消費和生產,因爲這些對於大多數開發人員熟悉的隱喻。需要IGobbler<Cow>的方法也可以接受IGobbler<Animal>,因爲可以吞噬(消耗)任何動物的狼吞虎嚥也可以吞噬牛。這裏的Gobbler是一種特定類型動物的消費者,所以它使用in標籤。

上述案例(反變換)看起來可能與直覺相反,但從RestaurantOwner的角度考慮,他想要一個Gobbler<Cow>。如果一個戈布勒爾只會吞噬豬,並且該餐廳的所有者試圖給他喂牛,那麼它就行不通。他只能接受不那麼挑剔的戈布勒,所以Gobbler<Animal>Gobbler<Herbivore>工作正常。

在另一方面,假設你有一個Farmer<Animal>出售的動物(具有返回IEnumerable<Animal>一個農場方法。)如果你有想要Buy(IEnumerable<Animal>)一個買方,那麼它可以接受Farmer<Cow>.Farm(),作爲買方願意購買任何生產的動物和母牛都是動物。這裏的農民是特定類型動物的生產者,所以它使用'out'標籤。

2

進出與參考和輸出沒有任何關係。

in關鍵字被用於描述在該接口的實例將消耗T的一個實例在該實例中,你鏈接的線

​​

創建火雞,可以餵驢到沉綿的驢不是一個QuadrupledCreature,但它來自它。所以你可以使用更專門的實例而不是基類作爲參數。

out關鍵字的工作方式大致相同,只是它用於描述產生東西而不是包含它的東西。

在同一示例中,線

ISpewer<Rodent> rs = new MouseSpewer(); 

創建ISpewer,其調用時噴出鼠標。鼠標不是齧齒動物,而是從中派生出來的,因此您可以使用生成的類生成比接口聲明的更專用的實例。

請注意在兩種情況下,最特殊的類是如何交換的。當使用in關鍵字時,你使用專用類作爲接口的通用參數,而在這種情況下,你使用基類作爲通用參數來告訴編譯器,儘管你創建了一個更專門的類,它應該把它當作基類來對待。

+0

這個聲明是如何工作的? IGobbler dg = new QuadrupedGobbler();類QuadrupedGobbler是否實現了接口,以便我們可以這樣做?事實上,這是我真正感到困惑的地方。 – q0987 2011-06-01 16:12:19

+1

QuadrupedGobbler實現通用的IGobbler接口,該接口通過協方差特別是接口的簽名,看起來像這樣'public interface IGobbler ...'允許IGobbler類型包含QuadrupedGobbler,因爲它實現了IGobbler。 如果你瞭解多態性,那麼它的概念並不太相似。 – 2013-07-11 21:10:35

相關問題