C#中的方法重载决策和通用/逆变接口

时间:2012-03-02 08:05:59

标签: c# overloading contravariance overload-resolution

我认为我的问题最好用我的类/接口层次结构的代码片段来解释:

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#行为。

3 个答案:

答案 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>

        }

      }