Warning: file_get_contents(/data/phpspider/zhask/data//catemap/0/amazon-s3/2.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
C# 多次实现协变接口:这种行为定义正确吗?_C#_Covariance - Fatal编程技术网

C# 多次实现协变接口:这种行为定义正确吗?

C# 多次实现协变接口:这种行为定义正确吗?,c#,covariance,C#,Covariance,给定以下协变泛型接口 public interface IContainer<out T> { T Value { get; } } 公共接口IContainer { T值{get;} } 我们可以为多个泛型类型创建一个多次实现此接口的类。在我感兴趣的场景中,这些泛型类型共享一个公共基类型 public interface IPrint { void Print(); } public class PrintA : IPrint { public void

给定以下协变泛型接口

public interface IContainer<out T>
{
    T Value { get; }
}
公共接口IContainer
{
T值{get;}
}
我们可以为多个泛型类型创建一个多次实现此接口的类。在我感兴趣的场景中,这些泛型类型共享一个公共基类型

public interface IPrint
{
    void Print();
}
public class PrintA : IPrint
{
    public void Print()
    {
        Console.WriteLine("A");
    }
}
public class PrintB : IPrint
{
    public void Print()
    {
        Console.WriteLine("B");
    }
}

public class SuperContainer : IContainer<PrintA>, IContainer<PrintB>
{
    PrintA IContainer<PrintA>.Value => new PrintA();
    PrintB IContainer<PrintB>.Value => new PrintB();
}
公共接口IPrint
{
作废打印();
}
公共类PrintA:IPrint
{
公开作废印刷品()
{
控制台。写入线(“A”);
}
}
公共类PrintB:IPrint
{
公开作废印刷品()
{
控制台。写入线(“B”);
}
}
公共级超级集装箱:IContainer,IContainer
{
printaicontainer.Value=>newprinta();
PrintB IContainer.Value=>newprintb();
}
现在,通过类型为
IContainer
的引用使用此类时,事情变得有趣起来

publicstaticvoidmain(字符串[]args)
{
IContainer容器=新的超级容器();
container.Value.Print();
}
这将编译并运行而不会出现问题,并打印“A”。我在以下文件中发现:

特定接口成员I.M的实现,其中I是 声明成员M的接口由 检查每个类或结构,从C开始,重复 C的每个连续基类,直到找到匹配项:

  • 如果是 包含显式接口成员实现的声明 如果匹配I和M,那么这个成员就是I.M的实现
  • 否则,如果S包含非静态公共成员的声明 如果匹配M,那么这个成员就是I.M的实现
第一个要点似乎是相关的,因为接口实现是显式的。然而,它并没有说明当有多个候选者时选择哪个实现

如果我们为
IContainer
实现使用公共权限,它会变得更加有趣:

public class SuperContainer : IContainer<PrintA>, IContainer<PrintB>
{
    public PrintA Value => new PrintA();
    PrintB IContainer<PrintB>.Value => new PrintB();
}
公共类超级容器:IContainer,IContainer
{
public PrintA Value=>new PrintA();
PrintB IContainer.Value=>newprintb();
}
现在,根据上面的规范,因为有一个通过
IContainer
的显式接口实现,所以我希望它打印“B”。然而,它使用的是公共财产,仍然打印“A”

类似地,如果我明确地实现了
IContainer
,并且通过公共属性实现了
IContainer
,它仍然会打印“A”

似乎输出唯一依赖的是接口的声明顺序。如果我将声明更改为

public class SuperContainer : IContainer<PrintB>, IContainer<PrintA>
公共类超级容器:IContainer,IContainer
一切都打印“B”


规范的哪一部分定义了这种行为,如果定义正确的话?

我在规范中找不到它,但您看到的是预期的
IContainer
IContainer
具有不同的完全限定名(无法找到有关如何形成此FQN的规范),因此编译器将
SuperContainer
识别为两个不同接口的实现类,每个接口都有一个
void Print()方法

因此,我们有两个不同的接口,每个接口包含一个具有相同签名的方法。当您在中链接时,
Print()
的实现首先通过查看
IContainer
、查找正确的映射,然后查看
IContainer
来选择

由于在
IContainer
中找到了正确的映射,
IContainer.Print()
用于
SuperContainer
IContainer
实现

来自同一规格(位于最底部):

基类的成员参与接口映射。在这个例子中

Class1中的方法F用于Class2接口1的实现


最后,是的,顺序决定了调用哪个
Print()
方法。

我认为它是在某个地方指定的,但我没有看到它。Eric Lippert很久以前就有了,所以有人在考虑这个问题。您究竟可以从规范中的哪个文本派生“Print()的实现首先通过查看
IContainer
,查找正确的映射,然后查看
IContainer
”?
public class SuperContainer : IContainer<PrintB>, IContainer<PrintA>
interface Interface1
{
   void F();
}
class Class1
{
   public void F() {}
   public void G() {}
}
class Class2: Class1, Interface1
{
   new public void G() {}
}