簡體   English   中英

類和結構之間存在差異作為協變類型參數

[英]There is a difference between classes and structs as covariant type parameters

如果在接口中用作協變類型參數的類型是struct ,則以下測試失敗(在最后一個Assert上),但如果它是class ,則成功。

interface IOuter { }
interface IOuter<out T> : IOuter { T Value { get; } }
interface IInner { }
struct Inner : IInner { }

class Outer : IOuter<Inner> { public Inner Value { get { return new Inner(); } } }

[TestMethod()]
public void ContravarianceTest()
{
    var a = new Outer();
    Assert.IsTrue(a is IOuter<Inner>);

    // Fails here if Inner is a struct. Succeeds if Inner is a class.
    Assert.IsTrue(a is IOuter<IInner>); 
}

為什么結構和類之間有區別

這種行為是設計但非常混亂 ,引用官方FAQ

僅當類型參數是引用類型時才支持差異。

通俗地說,因為將引用類型視為其他類型(祖先或后代)只涉及編譯器更新其內部簿記結構; 什么都不需要在運行時更改,因為所有引用類型的內存中表示具有相同的結構(在標准中,這涉及隱式引用轉換 )。

另一方面,值類型具有(可能)不同的內存中表示,因此將值類型A的實例視為值類型B的實例必然涉及運行時轉換。

因為結構是按值的。 沒有裝箱操作,你不能將結構“轉換”為另一個東西(接口)。

“out”只是關於強制轉換:它允許你將IEnumerable<MyClass>IEnumerable<MyClassBase> (你將枚舉相同的對象,具有不同的類型,沒有成本)......但這對於結構來說根本沒有意義(拳擊是必需的)。

如果類FooClass和struct FooStruct都實現IFoo ,則類型為FooClass的變量是對IFoo實現的引用 ,但FooStruct類型的變量本身就是 IFoo的實現。 可以使用引用類型進行協方差的原因是,如果T派生自U ,則對T每個引用都將是對U的引用; 如果對T的引用傳遞了一個期望引用U ,則接收的參數將是對U的引用,並且該方法不必關心它也是對T的引用。

協方差原因不與結構類型的工作是該類型的值Int32不是對實現一個堆對象的引用IComparable<Int32> --IT 的一個實現IComparable<Int32> 具有參數類型IComparable<Int32>將不會期望接收IComparable<Int32> - 它將期望接收引用。

注意,有些語言試圖假裝給出Int32 v1; Object v2 = v1;的聲明Int32 v1; Object v2 = v1; Int32 v1; Object v2 = v1; v1的類型和v2保存引用的對象的類型是同一個。 實際上,它們是居住在不同宇宙中的不同類型。 只要運行時環境看到派生自System.ValueType System.Enum以外的類,它就會在與堆類型分開的存儲位置類型的Universe中有效地定義第二種類型。 如果有人說IComprable<Int32> v3 = v1; ,正在做的是要求系統創建一個堆對象類型 Int32的實例,其內容從v1加載,並存儲到v3的引用。 雖然系統允許從結構類型到相應的堆對象類型的隱式轉換,以及另一種方式的顯式轉換,但這並不意味着變量和堆對象是相同的類型。 實際上,需要轉換的事實意味着它們不是。

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM