C# C语言中的方法重载解析和泛型/逆变接口#

C# C语言中的方法重载解析和泛型/逆变接口#,c#,overloading,contravariance,overload-resolution,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 : ITrans

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

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
公共接口ITransform//或-->在这里似乎没有什么区别
{
void变换(D数据);
}
接口ISelection{}
接口IValue:ISelection{}
公共接口IEditor:ITransform{}
公共接口ISelector:IEditor,ITransform{}
类值:IValue{…}
类编辑器:IEditor{…}//实现ITransform
类选择器:编辑器,ISelector{…}//实现ITransform
值v=新值();
选择器s1=新选择器();
ISelector s2=s1;
s1.变换(v);//解析为ITransform-->为什么?
s2.变换(v);//解析为ITransform-->确定
问题1:为什么
s1.转换(v)
解析为
ITransform
而不是第二种情况下的
ITransform

问题2:对于问题1,如果
ITransform
,似乎没有什么区别。但是在我的类/接口层次结构中使用
是否还存在其他问题?我有点怀疑,因为
ISelector
实现了
ITransform
ITransform
。由于
IValue
继承了
ISelection
,逆变是否会导致任何问题

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

在Q1上,我认为这是因为编译器将寻找较短的层次结构链以获得有效的重载。要在S1上获得ITransform,您必须更进一步

s1->Selector->ISelector->ITransform<Selector>
s1->Selector->Editor->IEditor->ITransform<IValue>
s1->Selector->ISelector->IEditor->ITransform<IValue>
s1->Selector->ISelector->ITransform
s1->选择器->编辑器->编辑工具->ITransform
s1->选择器->ISelector->IEditor->ITransform

我将查找要验证的源代码。

选择器类实现ITransform接口,这意味着您必须包含处理转换(ISelection)的代码。您的类也可以处理转换(IValue),但只能通过从编辑器类继承的方法来处理

它之所以选择ISelection变量,是因为它是在选择器类中显式声明的变量。要选择Transform(IValue),编译器必须假设您更愿意处理来自基类(编辑器)的调用

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

这些上下文中的每一个都定义了候选函数成员集 以及参数列表,如中所述 详情请参见上述章节。例如 方法调用的候选对象不包括标记为 重写(§7.4)、和基类中的方法(如果有的话)都不是候选方法 派生类中的方法适用(§7.6.5.1)。

问题1:为什么s1.Transform(v)解析为
ITransform
而不是像第二种情况那样进行
ITransform

对我来说,这将解析为
选择器.Transform
。它也应该是这样的:您说过它是一个选择器,选择器有一个名为Transform的公共方法,它需要一个ISelection。IValue扩展了我的选择。什么时候它会被强制转换成ITransform?我不相信这说明了任何矛盾,我认为这是隐性转换

问题2:对于问题1,如果 ITransform在中为
或不变

由于将泛型参数用作方法参数而不是返回类型,因此规则规定该参数必须是反向有效的,这将允许
输入
,而不允许
输出

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>

        }

      }
公共类示例
{
公共接口ITransform//或-->在这里似乎没有什么区别
{
void变换(D数据);//ITranform中的逆变式。
//D变换(字符串输入);//协方差正常
}
公共接口ISelection{}
公共接口IValue:ISelection{}
公共接口IEditor:ITransform{}
公共接口ISelector:IEditor,ITransform
{
新的void变换(i选择数据);
}
类值:IValue{}
类编辑器:IEditor
{
公共无效转换(IValue数据)
{
抛出新的NotImplementedException();
}
} 
类Foo:Editor、ISelector
{
公共无效转换(ISelection数据)
{
抛出新的NotImplementedException();
}
}  
公共空间
{
值v=新值();
Foo s1=新的Foo();
编辑s2=s1;
s1.Transform(v);//解析为Foo.Transform(ISelection)
s2.Transform(v);//解析为ITransform-->转换为IEditor,sig称之为ITransform
}
}

在这里,当我将D声明为逆变(in)时,两者都解析为ITransform。正如我所说的,ITransform是否为逆变似乎完全没有区别。对于s1,两个呼叫始终解析为ITransform。我不确定我们是否了解对方。。。你说的“两个电话都打”是什么意思?当ITransform是逆变式时,我确实有一个区别:s1.变换(v)和s2.变换(v)都解析为ITransform忘记这一点。“对于s1,两个调用”没有意义。至于你的“不同”:那正是我的问题。我原以为s1.Transform(v)将解析为ITransform,但它解析为ITransform。在这里,ITransform是否为逆变型没有区别。好吧,我明白你的意思了!我希望一些C#guru能给我们一个答案,我真的很好奇……嗯,我也这么想。但这真的有意义吗?这将打破我的观点,即“在方法重载中,编译器总是解析为具有最特定类型的重载”。如果能看到一些能证实这一点的消息来源,那就太好了。感谢