为什么C#中的Type.GetProperty()对于接口和基类的行为不同?

5
为什么Type.GetProperty(string)不能从基接口中获取属性,如果类型是一个接口?例如,下面的代码将打印:
System.String X
null
System.String X
System.String X

看起来不一致:

void Main()
{
    Console.WriteLine(typeof(I1).GetProperty("X"));
    Console.WriteLine(typeof(I2).GetProperty("X"));
    Console.WriteLine(typeof(C1).GetProperty("X"));
    Console.WriteLine(typeof(C2).GetProperty("X"));;
}

public interface I1 { string X { get; } }

public interface I2 : I1 { }

public class C1 { public string X { get { return "x"; } } }

public class C2 : C1 { }

编辑:支持Cole答案的运行时的另一个方面如下:

public class C : I2 {
    // not allowed: the error is
    // 'I2.X' in explicit interface declaration is not a member of interface
    string I2.X { get; set; }

    // allowed
    string I1.X { get; set; }
}

这与它是类还是接口无关。在一个中,X是私有的,在另一个中是公共的。 - Cory Nelson
接口可以被显式地实现(在实现类上“隐藏”方法),而类的公共属性始终是可见的。如果您在C1上显式实现I1,您将看到相同的行为,而如果您隐式实现它,则GetProperty将找到它。 - Dan Bryant
1
@CoryNelson 所有接口属性都是公共的。或者你是在说I2明确实现了I1,因此它的I1方法是私有的?如果是这样的话,那么为什么可以通过I2的实例访问X而不需要转换类型呢? - ChaseMedallion
@DanBryant:但是,如果您在C1上显式实现I1,则无法调用new C1().X。但是,如果您在C1上非显式地实现I2,并且您有一个变量I2 i2 = new C1(),则可以调用i2.X。这表明这不是I2显式实现I1的问题,但我可能错了。 - ChaseMedallion
@ChaseMedallion 你是正确的。暂时失常。 - Cory Nelson
1个回答

6
请记住,类继承和接口实现不同。
派生类和基类之间具有“is-a”关系。如果 D : B,则 D 是一个 B。如果 B 有一个属性,那么 D 也将定义为具有相同的属性,因为这就是这种关系的含义;D 的“实质”在某种意义上被其与 B 的关系所改变。
接口不提供实现,所以当你说 ID : IB 时,你并没有像类一样说 ID 是一个 IB。那意味着什么?ID 和 IB 不是“东西”;它们是“协议”。没有什么可以改变。相反,你要说“实现 ID 的类必须还提供 IB 的实现”。
ID 派生自 IB 的事实并不会改变 ID,因为它没有实质可改变。这只是意味着承诺履行由 ID 指定的合同的任何类也必须准备好遵守额外的一组要求。
记住这一点,如果 IB 提供属性 X,则对于“ID 是否具有属性 X?”这个问题的正确答案是“否”。ID 要求你还要实现 IB,IB 具有属性 X,但它本身没有属性 X。

你说的有道理,但是你能否基于某种C#文档或者类和接口在底层上的区别进行解释呢?你能否指出反射API中与这种区别一致的其他行为(除了GetMethod的明显并行)?例如,GetInterfaces()对于类和接口的工作方式是等效的。 - ChaseMedallion
2
@ChaseMedallion:正如您所指出的那样,您的问题涉及反射库的行为。没有任何要求规定反射的规则必须与C#、VB、F#或任何其他托管语言的规则相同。 C#规范对反射应该做什么没有任何说法;您应该查找的文档是反射库的文档。 - Eric Lippert
@ChaseMedallion:我认为GetProperty()同样适用于类和接口。它返回在类型上定义的属性。在ID : IB中,如果XIB上,接口实现的语义意味着X未在ID上定义。至于文档,我不知道有哪些。我只是试图根据我的继承语义理解来解释你所看到的行为。 - Cole Campbell

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接