![](/img/trans.png)
[英]Is there a built-in generic interface with covariant type parameter returned by an indexer?
[英]StackOverflowException by using explict interface implementation having covariant generic parameter
我正在使用協變泛型參數擴展現有的IClonable
接口。
public interface ICloneable<out T> : ICloneable
{
new T Clone();
}
現在我在基類中實現了這個接口。
public class Base : ICloneable<Base>
{
public string StrValue { get; set; }
Base ICloneable<Base>.Clone()
{
var result = (Base)FormatterServices.GetUninitializedObject(this.GetType());
result.StrValue = this.StrValue;
return result;
}
public virtual object Clone()
{
return ((ICloneable<Base>)this).Clone();
}
}
調用Clone()
按預期工作並返回具有相同值的基類的新實例。
我創建了一個Base
的派生類,它再次實現接口ICloneable<T>
以返回這個新類型:
public class Sub : Base, ICloneable<Sub>
{
public int IntValue { get; set; }
Sub ICloneable<Sub>.Clone()
{
var result = (Sub)base.Clone();
result.IntValue = this.IntValue;
return result;
}
public override object Clone()
{
return ((ICloneable<Sub>)this).Clone();
}
}
但是,如果我調用Clone()
上的一個實例Sub
我碰上StackOverflowException因為object Base.Clone()
調用Sub ICloneable<Sub>.Clone()
類的Sub
。
問題是協變泛型類型參數。 如果我刪除out
所有的作品如預期。
問題是為什么((ICloneable<Base>)this).Clone()
指向Sub.Clone()
?
共同和逆變只有語法糖,編譯器在派生層次結構中搜索最低可能的類型嗎? 這意味着編譯器將ICloneable<Base>
更改為ICloneable<Sub>
。
我沒有找到任何解釋這種行為的官方理由。
測試代碼(不包括接口和Base
和Sub
):
var b = new Sub { StrValue = "Hello World.", IntValue = 42 };
var b2 = (Base)b.Clone();
共同和逆變只有語法糖,編譯器在派生層次結構中搜索最低可能的類型嗎?
Co / contravariance與語法糖無關。 它允許您在編譯時傳遞“更小”,更具體的類型(協方差)和更大的(逆變)與特定的編譯器限制。
因為您的T
參數被標記為out
,所以CLR將查看Clone
任何覆蓋實現的運行時。
編譯時綁定是callvirt
的base.Clone
,它不會改變:
.method public hidebysig newslot virtual
instance object Clone () cil managed
{
// Method begins at RVA 0x2089
// Code size 7 (0x7)
.maxstack 8
IL_0000: ldarg.0
IL_0001: callvirt instance !0 class ICloneable`1<class Base>::Clone()
IL_0006: ret
} // end of method Base::Clone
運行時是多態發生的地方 。
,取消的事實out
調用基強調,准確。
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.