[英]Method overload resolution and generic/contravariant interfaces in C#
我認為我的問題最好用我的類/接口層次結構的代碼片段來解釋:
public interface ITransform<D> // or <in D> --> seems to make no difference here
{
void Transform(D data);
}
interface ISelection {}
interface IValue : ISelection {}
public interface IEditor : ITransform<IValue> {}
public interface ISelector : IEditor, ITransform<ISelection> {}
class Value : IValue { ... }
class Editor : IEditor { ... } // implements ITransform<IValue>
class Selector : Editor, ISelector { ... } // implements ITransform<ISelection>
Value v = new Value();
Selector s1 = new Selector();
ISelector s2 = s1;
s1.Transform(v); // resolves to ITransform<ISelection> --> WHY?
s2.Transform(v); // resolves to ITransform<IValue> --> OK
問題1:為什么s1.Transform(v)
解析為ITransform<ISelection>
而不是像第二種情況那樣解決ITransform<IValue>
?
問題2:對於問題1,如果ITransform
是<D>
或<in D>
,似乎沒有區別。 但是你在我的類/接口層次結構中使用<in D>
是否看到任何其他問題? 由於ISelector
實現了ITransform<IValue>
和ITransform<ISelection>
我有點懷疑。 由於IValue
繼承了ISelection
因此可能會出現IValue
問題嗎?
編輯只是為了讓你知道:我目前正在使用Silverlight 4,但我認為這是一般的C#行為。
您的Selector類實現了ITransform接口,這意味着您必須包含處理Transform(ISelection)的代碼。 您的類也可以處理Transform(IValue),但僅限於Editor類中的繼承方法。
它選擇ISelection變體的原因是因為這是在Selector類中顯式聲明的變體。 要選擇Transform(IValue),編譯器必須假設您更願意處理來自基類(編輯器)的調用。
編輯:C#規范的一些背景知識。
這些上下文中的每一個都以其自己獨特的方式定義候選函數成員集和參數列表,如上面列出的部分中詳細描述的。 例如,方法調用的候選集不包括標記為override的方法(第7.4節), 如果派生類中的任何方法適用(第7.6.5.1節),則基類中的方法不是候選方法。
在Q1,我認為它是因為編譯器將尋找較短的層次結構鏈來獲得有效的重載。 要在S1上獲得ITransform,您將不得不走得更遠。
s1->Selector->ISelector->ITransform<Selector>
s1->Selector->Editor->IEditor->ITransform<IValue>
s1->Selector->ISelector->IEditor->ITransform<IValue>
我會找一個來源驗證。
問題1:為什么s1.Transform(v)解析為
ITransform<ISelection>
而不是像第二種情況那樣解決ITransform<IValue>
?
對我來說,這解析為Selector.Transform<ISelection>
。 它應該:你說它是一個Selector,而Selector有一個名為Transform的公共方法,它需要一個ISelection。 IValue擴展了ISelection。 它何時會被強制轉換為ITransform? 我不相信這說明任何逆轉,我認為這是隱含的轉換。
問題2:對於問題1,如果ITransform
in
或不變,則似乎沒有任何區別
因為你使用泛型參數的方法不精氨酸返回類型,規則規定,該參數必須是contravariantly有效的,這將允許in
,並禁止out
。
public class Example
{
public interface ITransform<D> // or <in D> --> seems to make no difference here
{
void Transform(D data); //contravariant in ITranform<out D>.
//D Transform(string input); //covariance ok
}
public interface ISelection { }
public interface IValue : ISelection { }
public interface IEditor : ITransform<IValue> { }
public interface ISelector : IEditor, ITransform<ISelection>
{
new void Transform(ISelection data);
}
class Value : IValue { }
class Editor : IEditor
{
public void Transform(IValue data)
{
throw new NotImplementedException();
}
}
class Foo : Editor, ISelector
{
public void Transform(ISelection data)
{
throw new NotImplementedException();
}
}
public void Whatever()
{
Value v = new Value();
Foo s1 = new Foo();
IEditor s2 = s1;
s1.Transform(v); // resolves to Foo.Tranform(ISelection)
s2.Transform(v); // resolves to ITransform<IValue> --> cast into IEditor, which sig says ITransform<IValue>
}
}
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.