我认为我的问题最好用我的类/接口层次结构的代码片段来解释:
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
?
修改 只是为了让你知道:我目前正在使用Silverlight 4,但我认为这是一般的C#行为。
答案 0 :(得分:2)
您的Selector类实现了ITransform接口,这意味着您必须包含处理Transform(ISelection)的代码。您的类也可以处理Transform(IValue),但只能使用Editor类中的继承方法。
选择ISelection变体的原因是因为这是在Selector类中显式声明的变体。要选择Transform(IValue),编译器必须假设您更愿意处理来自基类(编辑器)的调用。
编辑:来自C#规范的一些背景知识。
这些上下文中的每一个都定义了候选函数成员集 和自己独特方式的参数列表,如中所述 上面列出的部分中的详细信息。例如,一组 方法调用的候选者不包括标记的方法 覆盖(第7.4节),和基类中的方法不是候选者(如果有的话) 派生类中的方法适用(第7.6.5.1节)。
答案 1 :(得分:0)
在Q1上我认为是因为编译器会寻找较短的层次结构链来获得有效的重载。要在S1上获得IT变换,您必须更进一步。
s1->Selector->ISelector->ITransform<Selector>
s1->Selector->Editor->IEditor->ITransform<IValue>
s1->Selector->ISelector->IEditor->ITransform<IValue>
我会寻找要验证的来源。
答案 2 :(得分:0)
问题1:为什么s1.Transform(v)解析为
ITransform<ISelection>
而不是像第二种情况那样ITransform<IValue>
?
对我来说,这解析为Selector.Transform<ISelection>
。它应该:你说它是一个Selector,而Selector有一个名为Transform的公共方法,它需要一个ISelection。 IValue扩展了ISelection。它何时会被强制转换为ITransform?我不相信这说明了任何矛盾,我认为这是隐含的转换。
问题2:问题1似乎没有区别 ITransform是
in
或不变的
因为您使用泛型参数作为方法而不是返回类型,规则规定参数必须是违反有效的,这将允许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>
}
}