C# 这是斯巴达,还是?
以下是一个采访问题。我想出了一个解决办法,但我不知道为什么它会起作用C# 这是斯巴达,还是?,c#,inheritance,types,namespaces,C#,Inheritance,Types,Namespaces,以下是一个采访问题。我想出了一个解决办法,但我不知道为什么它会起作用 问题: 在不修改Sparta类的情况下,编写一些代码,使MakeItReturnFalsereturnfalse public class Sparta : Place { public bool MakeItReturnFalse() { return this is Sparta; } } 我的解决方案:(扰流板) 公共上课场所 { 公共接口斯巴达{} } 但是为什么MakeI
问题: 在不修改
Sparta
类的情况下,编写一些代码,使MakeItReturnFalse
returnfalse
public class Sparta : Place
{
public bool MakeItReturnFalse()
{
return this is Sparta;
}
}
我的解决方案:(扰流板)
公共上课场所
{
公共接口斯巴达{}
}
但是为什么MakeItReturnFalse()
中的Sparta
引用的是{namespace}.Place.Sparta
而不是{namespace}.Sparta
但是为什么MakeItReturnFalse()
中的Sparta
引用的是{namespace}.Place.Sparta
而不是{namespace}.Sparta
基本上,因为名称查找规则就是这么说的。在C#5规范中,相关命名规则见第3.8节(“名称空间和类型名称”)
前两个项目符号(截断和注释)为:
- 如果名称空间或类型名称的格式为
I
或I
[在本例中K=0]:
- 如果K为零,并且名称空间或类型名称出现在泛型方法声明中[不,没有泛型方法]
- 否则,如果名称空间或类型名称出现在类型声明中,则对于每个实例类型T(§10.3.1),从该类型声明的实例类型开始,继续到每个封闭类或结构声明的实例类型(如果有):
- 如果
K
为零,并且T
的声明包含名为I
的类型参数,则命名空间或类型名称引用该类型参数[Nope]
- 否则,如果名称空间或类型名称出现在类型声明的主体中,并且
T
或其任何基本类型包含具有名称I
和K
类型参数的嵌套可访问类型,则名称空间或类型名称引用使用给定类型参数构造的类型[宾果!]
- 如果前面的步骤不成功,则对于每个名称空间
N
,从名称空间或类型名称所在的名称空间开始,继续执行每个封闭名称空间(如果有)并以全局名称空间结束,将计算以下步骤,直到找到实体:
- 如果
K
为零,并且I
是N
中命名空间的名称,则[是的,那会成功]
因此,最后一个要点是,如果第一个要点没有找到任何东西,那么它将拾取Sparta
类。。。但是当基类<代码>位置<代码>定义一个接口<代码>斯巴达< /代码>时,它会在我们考虑<代码>斯巴达< /Cord>类> 之前找到。
请注意,如果将嵌套类型Place.Sparta
设置为类而不是接口,它仍会编译并返回false
——但编译器会发出警告,因为它知道Sparta
的实例永远不会是类Place.Sparta
的实例。同样,如果您保留Place.Sparta
接口,但将Sparta
类密封,您将收到警告,因为没有Sparta
实例可以实现该接口。将名称解析为其值时,定义的“接近性”用于解决歧义。任何“最接近”的定义都是被选择的定义
接口Sparta
在基类中定义。类Sparta
在包含的命名空间中定义。在基类中定义的东西比在同一名称空间中定义的东西“更接近”。漂亮的问题!我想为那些不每天做C#的人补充一个稍微长一点的解释。。。因为这个问题很好地提醒了我们一般的名称解析问题
以原始代码为例,通过以下方式稍微修改:
- 让我们打印出类型名称,而不是像原始表达式那样比较它们(即
返回这是Sparta
)
- 让我们在
Place
超类中定义接口Athena
,以说明接口名称解析李>
- 让我们也打印出
this
的类型名,因为它绑定在Sparta
类中,只是为了让一切都非常清楚
代码如下所示:
public class Place {
public interface Athena { }
}
public class Sparta : Place
{
public void printTypeOfThis()
{
Console.WriteLine (this.GetType().Name);
}
public void printTypeOfSparta()
{
Console.WriteLine (typeof(Sparta));
}
public void printTypeOfAthena()
{
Console.WriteLine (typeof(Athena));
}
}
现在我们创建一个Sparta
对象并调用这三个方法
public static void Main(string[] args)
{
Sparta s = new Sparta();
s.printTypeOfThis();
s.printTypeOfSparta();
s.printTypeOfAthena();
}
}
我们得到的结果是:
Sparta
Athena
Place+Athena
但是,如果我们修改Place类并定义接口Sparta:
public class Place {
public interface Athena { }
public interface Sparta { }
}
然后就是这个Sparta
——接口——首先可用于名称查找机制,我们的代码输出将更改为:
Sparta
Place+Sparta
Place+Athena
因此,仅通过在超类中定义Sparta接口,我们就有效地搞乱了MakeItReturnFalse
函数定义中的类型比较,而Sparta接口首先通过名称解析找到
但为什么C#选择在名称解析中对超类中定义的接口进行优先级排序@琼斯杰知道!如果你阅读他的答案,你会得到C#中名称解析协议的详细信息。,想象一下,如果名称查找不能以这种方式工作。然后,如果有人碰巧添加了同名的顶级类,则包含内部类的工作代码将被破坏。@dan04:但是,如果有人碰巧添加了与顶级类同名的嵌套类,则不包含嵌套类的工作代码将被破坏。所以这并不完全是一个“赢”的场景。@JonSkeet我想说添加这样一个嵌套类是一个改变,在这个改变中