[英]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>);
}
為什么結構和類之間有區別 ?
通俗地說,因為將引用類型視為其他類型(祖先或后代)只涉及編譯器更新其內部簿記結構; 什么都不需要在運行時更改,因為所有引用類型的內存中表示具有相同的結構(在標准中,這涉及隱式引用轉換 )。
另一方面,值類型具有(可能)不同的內存中表示,因此將值類型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.