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() {}
}