7

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

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)resolve toITransform<ISelection>而不是to ?ITransform<IValue>

问题 2:ITransform对于问题 1,如果is<D>或似乎没有区别<in D><in D>但是您是否看到在我的类/界面层次结构中使用的任何其他问题?我有点怀疑,因为ISelector哪个实现ITransform<IValue>ITransform<ISelection>. IValue由于继承,逆变可能会在这里引起任何问题ISelection吗?

编辑 只是为了让您知道:我目前正在使用 Silverlight 4,但我认为这是一般的 C# 行为。

4

3 回答 3

2

您的 Selector 类实现了 ITransform 接口,这意味着您必须包含处理 Transform(ISelection) 的代码。您的类也可以处理 Transform(IValue) 但只能通过从 Editor 类继承的方法。

它选择 ISelection 变体的原因是因为它是在 Selector 类中明确声明的变体。要选择 Transform(IValue),编译器必须假设您宁愿处理来自基类(编辑器)的调用。

编辑:来自 C# 规范的一些背景。

这些上下文中的每一个都以自己独特的方式定义候选函数成员集和参数列表,如上面列出的部分中详细描述的那样。例如,方法调用的候选集不包括标记为覆盖的方法(第 7.4 节),如果派生类中的任何方法适用(第 7.6.5.1 节),则基类中的方法不是候选方法。

于 2012-03-02T10:11:40.133 回答
0

在第一季度,我认为这是因为编译器会寻找较短的层次结构链来获得有效的重载。要在 S1 上获得 ITransform,您必须走得更远。

s1->Selector->ISelector->ITransform<Selector>
s1->Selector->Editor->IEditor->ITransform<IValue>
s1->Selector->ISelector->IEditor->ITransform<IValue>

我会寻找来源来验证。

于 2012-03-02T08:56:11.477 回答
0

问题 1:为什么 s1.Transform(v)在第二种情况下 解析为ITransform<ISelection> 而不是解析?ITransform<IValue>

对我来说,这解决了Selector.Transform<ISelection>. 它也应该:你说它是一个 Selector,Selector 有一个名为 Transform 的公共方法,它需要一个 ISelection。IValue 扩展了 ISelection。它什么时候会被强制转换为 ITransform?我不相信这说明了任何逆变,我认为这是隐式转换。

in问题 2:对于问题 1,如果 ITransform 是或不变的,似乎没有区别

由于您将泛型参数用作方法 arg 而不是返回类型,因此规则规定该参数必须是逆变有效的,这将允许in, 和 disallow 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>

        }

      }
于 2012-03-02T10:45:38.983 回答