给定以下协变泛型接口(interface)
public interface IContainer<out T>
{
T Value { get; }
}
我们可以创建一个类,为多个泛型类型多次实现这个接口(interface)。在我感兴趣的场景中,这些泛型类型共享一个公共(public)基类型。
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();
}
现在,当通过 IContainer<IPrint>
类型的引用使用此类时,事情会变得有趣起来。 .
public static void Main(string[] args)
{
IContainer<IPrint> container = new SuperContainer();
container.Value.Print();
}
这可以毫无问题地编译和运行并打印“A”。我在 spec 中找到了什么:
The implementation of a particular interface member I.M, where I is the interface in which the member M is declared, is determined by examining each class or struct S, starting with C and repeating for each successive base class of C, until a match is located:
- If S contains a declaration of an explicit interface member implementation that matches I and M, then this member is the implementation of I.M.
- Otherwise, if S contains a declaration of a non-static public member that matches M, then this member is the implementation of I.M.
第一个要点似乎是相关的,因为接口(interface)实现是显式的。但是,当有多个候选者时,它没有说明选择哪个实现。
如果我们为 IContainer<PrintA>
使用公共(public)属性,它会变得更加有趣实现:
public class SuperContainer : IContainer<PrintA>, IContainer<PrintB>
{
public PrintA Value => new PrintA();
PrintB IContainer<PrintB>.Value => new PrintB();
}
现在,根据上面的规范,因为通过 IContainer<PrintB>
有一个明确的接口(interface)实现,我希望这会打印“B”。但是,它使用公共(public)属性并仍然打印“A”。
同样,如果我改为执行 IContainer<PrintA>
明确地和IContainer<PrintB>
通过公共(public)属性(property),它仍然打印“A”。
看起来输出唯一依赖的是接口(interface)声明的顺序。如果我将声明更改为
public class SuperContainer : IContainer<PrintB>, IContainer<PrintA>
一切都打印“B”!
规范的哪一部分定义了这种行为,如果它被正确定义的话?
最佳答案
我无法在规范中找到它,但您所看到的是预期的。 IContainer<PrintA>
和 IContainer<PrintB>
具有不同的完全限定名称(无法找到关于如何形成此 FQN 的规范),因此编译器识别 SuperContainer
作为两个不同接口(interface)的实现类,每个接口(interface)都有一个 void Print();
方法。
因此,我们有两个不同的接口(interface),每个接口(interface)都包含一个具有相同签名的方法。正如您在 spec (13.4.2) 中链接的那样实现Print()
首先通过查看 IContainer<PrintA>
选择,寻找合适的映射,然后查看IContainer<PrintB>
.
由于在 IContainer<PrintA>
中找到了正确的映射, IContainer<PrintA>.Print()
用于 SuperContainer
对 IContainer<PrintB>
的实现.
来自相同的规范(位于最底部):
The members of a base class participate in interface mapping. In the example
interface Interface1
{
void F();
}
class Class1
{
public void F() {}
public void G() {}
}
class Class2: Class1, Interface1
{
new public void G() {}
}
the method F in Class1 is used in Class2's implementation of Interface1.
所以最后,是的,顺序决定了哪个 Print()
方法被调用。
关于c# - 多次实现协变接口(interface) : is this behavior properly defined?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/34756842/