第七色在线视频,2021少妇久久久久久久久久,亚洲欧洲精品成人久久av18,亚洲国产精品特色大片观看完整版,孙宇晨将参加特朗普的晚宴

為了賬號安全,請及時綁定郵箱和手機立即綁定
已解決430363個問題,去搜搜看,總會有你想問的

仍然對協(xié)方差和矛盾和輸入/輸出感到困惑

仍然對協(xié)方差和矛盾和輸入/輸出感到困惑

C#
慕村225694 2019-10-08 10:02:47
好的,我在stackoverflow上閱讀了有關(guān)該主題的內(nèi)容,觀看了&this,但是對于co / contra-variance還是有些困惑。從這里協(xié)方差允許在原始類型僅用于“輸出”位置(例如,作為返回值)的API中替換“較大”(較不具體)的類型。協(xié)變性允許在原始類型僅用于“輸入”位置的API中替換“較小”(更具體)的類型。我知道這與類型安全有關(guān)。關(guān)于這in/out件事。我可以說我in何時需要寫它,out何時需要它只讀。和in裝置,禁忌方差,out協(xié)方。但是根據(jù)上面的解釋...與此例如,List<Banana>不能將a視為a,List<Fruit>因為  list.Add(new Apple())它對List有效,但對無效List<Banana>。所以不應(yīng)該,如果我要使用in/要寫入該對象,則它必須更大,更通用。我知道有人問過這個問題,但仍然很困惑。
查看完整描述

3 回答

?
aluckdog

TA貢獻1847條經(jīng)驗 獲得超7個贊

C#4.0中的協(xié)方差和協(xié)方差都涉及使用派生類而不是基類的能力。in / out關(guān)鍵字是編譯器提示,用于指示是否將類型參數(shù)用于輸入和輸出。


協(xié)方差

C#4.0中的協(xié)方差由out關(guān)鍵字輔助,這意味著使用outtype參數(shù)的派生類的泛型類型是可以的。因此


IEnumerable<Fruit> fruit = new List<Apple>();

由于Apple是Fruit,List<Apple>可以安全地用作IEnumerable<Fruit>


逆差

矛盾是in關(guān)鍵字,它表示輸入類型,通常在委托中。原理是相同的,這意味著委托可以接受更多派生類。


public delegate void Func<in T>(T param);

這意味著如果我們有一個Func<Fruit>,可以將其轉(zhuǎn)換為Func<Apple>。


Func<Fruit> fruitFunc = (fruit)=>{};

Func<Apple> appleFunc = fruitFunc;

如果它們基本上是相同的東西,為什么將它們稱為協(xié)/逆方差?

因為即使原理相同,也可以安全地從派生類型轉(zhuǎn)換為基類,但在輸入類型上使用時,我們可以安全地將較少派生類型(Func<Fruit>)強制轉(zhuǎn)換為更多派生類型(Func<Apple>),這很有意義,因為任何需要Fruit,也可以服用Apple。


查看完整回答
反對 回復 2019-10-08
?
翻過高山走不出你

TA貢獻1875條經(jīng)驗 獲得超3個贊

讓我分享我對這個話題的看法。


免責聲明:忽略空分配,我使用它們來使代碼保持相對簡短,并且它們足以查看編譯器想要告訴我們什么。

讓我們從類的層次結(jié)構(gòu)開始:

class Animal { }


class Mammal : Animal { }


class Dog : Mammal { }

現(xiàn)在定義一些接口,來說明什么in和out通用修飾符真正做到:

interface IInvariant<T>

{

    T Get(); // ok, an invariant type can be both put into and returned

    void Set(T t); // ok, an invariant type can be both put into and returned

}


interface IContravariant<in T>

{

    //T Get(); // compilation error, cannot return a contravariant type

    void Set(T t); // ok, a contravariant type can only be **put into** our class (hence "in")

}


interface ICovariant<out T>

{

    T Get(); // ok, a covariant type can only be **returned** from our class (hence "out")

    //void Set(T t); // compilation error, cannot put a covariant type into our class

}

好的,如果對接口in和out修飾符有限制,為什么還要麻煩使用它們呢?讓我們來看看:


不變性

讓我們從不變性開始(沒有in,沒有out修飾符)


不變性實驗

考慮 IInvariant<Mammal>


IInvariant<Mammal>.Get() -返回哺乳動物

IInvariant<Mammal>.Set(Mammal) -接受哺乳動物

如果我們嘗試:IInvariant<Mammal> invariantMammal = (IInvariant<Animal>)null?


呼叫者都IInvariant<Mammal>.Get()希望有哺乳動物,但是IInvariant<Animal>.Get()-會返回動物。并不是每個動物都是哺乳動物,所以它是不兼容的。

不管誰打電話,都IInvariant<Mammal>.Set(Mammal)希望哺乳動物能夠通過。由于IInvariant<Animal>.Set(Animal)可以接受任何動物(包括哺乳動物),因此兼容

結(jié)論:這種分配是不相容的

而如果我們嘗試:IInvariant<Mammal> invariantMammal = (IInvariant<Dog>)null?


呼叫者IInvariant<Mammal>.Get()期望有哺乳動物,IInvariant<Dog>.Get()-會返回一只狗,每只狗都是一只哺乳動物,因此是兼容的。

不管誰打電話,都IInvariant<Mammal>.Set(Mammal)希望哺乳動物能夠通過。由于IInvariant<Dog>.Set(Dog)接受只狗(而不是每個哺乳動物如狗),這是不兼容的。

結(jié)論:這種分配是不相容的

讓我們檢查是否正確


IInvariant<Animal> invariantAnimal1 = (IInvariant<Animal>)null; // ok

IInvariant<Animal> invariantAnimal2 = (IInvariant<Mammal>)null; // compilation error

IInvariant<Animal> invariantAnimal3 = (IInvariant<Dog>)null; // compilation error


IInvariant<Mammal> invariantMammal1 = (IInvariant<Animal>)null; // compilation error

IInvariant<Mammal> invariantMammal2 = (IInvariant<Mammal>)null; // ok

IInvariant<Mammal> invariantMammal3 = (IInvariant<Dog>)null; // compilation error


IInvariant<Dog> invariantDog1 = (IInvariant<Animal>)null; // compilation error

IInvariant<Dog> invariantDog2 = (IInvariant<Mammal>)null; // compilation error

IInvariant<Dog> invariantDog3 = (IInvariant<Dog>)null; // ok

這一點很重要:值得注意的是,根據(jù)泛型類型參數(shù)在類層次結(jié)構(gòu)中是較高還是較低,泛型類型本身由于不同的原因而不兼容。


好的,讓我們找出如何利用它。


協(xié)方差(out)

使用out通用修飾符時,您將具有協(xié)方差(請參見上文)


如果我們的類型看起來像:ICovariant<Mammal>,則聲明兩件事:


我的一些方法返回了哺乳動物(因此是out通用修飾符)-這很無聊

我的方法都不接受哺乳動物-盡管這很有趣,因為這是通用修飾符施加的實際限制out

我們?nèi)绾螐膐ut修飾符限制中受益?回顧上面的“不變性實驗”的結(jié)果?,F(xiàn)在嘗試看看對協(xié)方差進行相同的實驗會發(fā)生什么?


協(xié)方差實驗

如果我們嘗試:ICovariant<Mammal> covariantMammal = (ICovariant<Animal>)null?


呼叫者都ICovariant<Mammal>.Get()希望有哺乳動物,但是ICovariant<Animal>.Get()-會返回動物。并不是每個動物都是哺乳動物,所以它是不兼容的。

ICovariant.Set(Mammal) -由于out修改器的限制,這不再是一個問題!

結(jié)論這樣的分配是不相容的

而如果我們嘗試:ICovariant<Mammal> covariantMammal = (ICovariant<Dog>)null?


呼叫者ICovariant<Mammal>.Get()期望有哺乳動物,ICovariant<Dog>.Get()-會返回一只狗,每只狗都是一只哺乳動物,因此是兼容的。

ICovariant.Set(Mammal) -由于out修改器的限制,這不再是一個問題!

結(jié)論這樣的分配是兼容的

讓我們用代碼進行確認:


ICovariant<Animal> covariantAnimal1 = (ICovariant<Animal>)null; // ok

ICovariant<Animal> covariantAnimal2 = (ICovariant<Mammal>)null; // ok!!!

ICovariant<Animal> covariantAnimal3 = (ICovariant<Dog>)null; // ok!!!


ICovariant<Mammal> covariantMammal1 = (ICovariant<Animal>)null; // compilation error

ICovariant<Mammal> covariantMammal2 = (ICovariant<Mammal>)null; // ok

ICovariant<Mammal> covariantMammal3 = (ICovariant<Dog>)null; // ok!!!


ICovariant<Dog> covariantDog1 = (ICovariant<Animal>)null; // compilation error

ICovariant<Dog> covariantDog2 = (ICovariant<Mammal>)null; // compilation error

ICovariant<Dog> covariantDog3 = (ICovariant<Dog>)null; // ok

協(xié)方差(in)

使用in泛型修飾符時,您會產(chǎn)生矛盾(請參見上文)


如果我們的類型看起來像:IContravariant<Mammal>,則聲明兩件事:


我的一些方法接受哺乳動物(因此in通用修飾符)-這很無聊

我的方法都沒有返回哺乳動物-盡管這很有趣,因為這是通用修飾符施加的實際限制in

協(xié)方差實驗

如果我們嘗試:IContravariant<Mammal> contravariantMammal = (IContravariant<Animal>)null?


IContravariant<Mammal>.Get()-由于in修改器的限制,這不再是問題!

不管誰打電話,都IContravariant<Mammal>.Set(Mammal)希望哺乳動物能夠通過。由于IContravariant<Animal>.Set(Animal)可以接受任何動物(包括哺乳動物),因此兼容

結(jié)論:這樣的分配是兼容的

而如果我們嘗試:IContravariant<Mammal> contravariantMammal = (IContravariant<Dog>)null?


IContravariant<Mammal>.Get()-由于in修改器的限制,這不再是問題!

不管誰打電話,都IContravariant<Mammal>.Set(Mammal)希望哺乳動物能夠通過。由于IContravariant<Dog>.Set(Dog)接受只狗(而不是每個哺乳動物如狗),這是不兼容的。

結(jié)論:這種分配是不相容的

讓我們用代碼進行確認:


IContravariant<Animal> contravariantAnimal1 = (IContravariant<Animal>)null; // ok

IContravariant<Animal> contravariantAnimal2 = (IContravariant<Mammal>)null; // compilation error

IContravariant<Animal> contravariantAnimal3 = (IContravariant<Dog>)null; // compilation error


IContravariant<Mammal> contravariantMammal1 = (IContravariant<Animal>)null; // ok!!!

IContravariant<Mammal> contravariantMammal2 = (IContravariant<Mammal>)null; // ok

IContravariant<Mammal> contravariantMammal3 = (IContravariant<Dog>)null; // compilation error


IContravariant<Dog> contravariantDog1 = (IContravariant<Animal>)null; // ok!!!

IContravariant<Dog> contravariantDog2 = (IContravariant<Mammal>)null; // ok!!!

IContravariant<Dog> contravariantDog3 = (IContravariant<Dog>)null; // ok

順便說一句,這有點違反直覺,不是嗎?


// obvious

Animal animal = (Dog)null; // ok

Dog dog = (Animal)null; // compilation error, not every Animal is a Dog


// but this looks like the other way around

IContravariant<Animal> contravariantAnimal = (IContravariant<Dog>) null; // compilation error

IContravariant<Dog> contravariantDog = (IContravariant<Animal>) null; // ok

為什么不兼得?

因此,我們可以同時使用in和out一般的修飾?-顯然不是。


為什么?回顧一下限制in和out修飾符施加的限制。如果我們想使我們的泛型類型參數(shù)既協(xié)變又是協(xié)變的,我們基本上可以說:


接口的所有方法均未返回 T

我們接口的方法均不接受 T

這實質(zhì)上會使我們的通用接口成為非通用接口。


如何記住它?

你可以用我的把戲:)


“協(xié)變量”比“ contravaraint”短,這與它們的修飾符的長度相反(分別為“ out”和“ in”)

相反 varaint有點反直觀(請參見上面的示例)


查看完整回答
反對 回復 2019-10-08
  • 3 回答
  • 0 關(guān)注
  • 364 瀏覽

添加回答

舉報

0/150
提交
取消
微信客服

購課補貼
聯(lián)系客服咨詢優(yōu)惠詳情

幫助反饋 APP下載

慕課網(wǎng)APP
您的移動學習伙伴

公眾號

掃描二維碼
關(guān)注慕課網(wǎng)微信公眾號