这是斯巴达,还是它?

bud*_*udi 121 c# inheritance types namespaces

以下是面试问题.我想出了一个解决方案,但我不确定它为什么会起作用.


题:

在不修改Sparta类的情况下,编写一些MakeItReturnFalse返回的代码false.

public class Sparta : Place
{
    public bool MakeItReturnFalse()
    {
        return this is Sparta;
    }
}
Run Code Online (Sandbox Code Playgroud)

我的解决方案:(SPOILER)

public class Place
{
public interface Sparta { }
}

但为什么SpartaMakeItReturnFalse()提到{namespace}.Place.Sparta而不是{namespace}.Sparta

Jon*_*eet 117

但为什么SpartaMakeItReturnFalse()提到{namespace}.Place.Sparta而不是{namespace}.Sparta

基本上,因为这就是名称查找规则所说的内容.在C#5规范中,相关的命名规则在3.8节("命名空间和类型名称")中.

前几个子弹 - 截断和注释 - 读取:

  • 如果namespace-or-type-name的形式I或形式I<A1, ..., AK> [在我们的例子中K = 0]:
    • 如果K为零且namespace-or-type-name出现在泛型方法声明中[nope,没有泛型方法]
    • 否则,如果namespace-or-type-name出现在类型声明中,那么对于每个实例类型T(第10.3.1节),从该类型声明的实例类型开始并继续每个封闭类的实例类型或结构声明(如果有):
      • 如果K为零且声明T包含带有name的类型参数I,则namespace-or-type-name引用该类型参数.[不]
      • 否则,如果namespace-or-type-name出现在类型声明的主体中,T 或者它的任何基类型包含具有name IKtype参数的嵌套可访问类型,那么namespace-or-type-name指的是使用给定类型参数构造的类型.[答对了!]
  • 如果前面的步骤不成功,那么对于每个命名空间N,从发生namespace-or-type-name的命名空间开始,继续使用每个封闭的命名空间(如果有的话),并以全局命名空间结束,将评估以下步骤直到找到实体:
    • 如果K为零并且I是名称空间中的名称N,那么... [是的,那成功]

因此,如果第一个项目符号没有找到任何内容,那么最后一个项目就是获取Sparta 该类 ...但是当基类Place定义一个接口时Sparta,它会我们考虑Sparta该类之前找到它.

请注意,如果您将嵌套类型设置Place.Sparta为类而不是接口,它仍会编译并返回false- 但编译器会发出警告,因为它知道实例Sparta永远不会是该类的实例Place.Sparta.同样,如果您保留Place.Sparta一个接口但是创建Sparta该类sealed,您将收到警告,因为没有Sparta实例可以实现该接口.

  • 另一个随机观察:使用原始的`Sparta`类,`这是Place`返回`true`.但是,将`public interface Place {}`添加到`Sparta`类会导致`这是Place`返回`false`.让我的头旋转. (2认同)

Ser*_*rvy 22

将名称解析为其值时,定义的"接近度"用于解决歧义.无论"最接近"的定义是选择的定义.

接口Sparta在基类中定义.该类Sparta在包含名称空间中定义.在基类中定义的内容比在同一名称空间中定义的内容"更接近".

  • @JonSkeet虽然这不仅仅是一个略有不同的幌子中的脆弱基类问题吗? (2认同)