以下是一个面试问题。我想出了一个解决方案,但我不确定它为什么有效。
问题:
在不修改Sparta
类的情况下,编写一些代码使MakeItReturnFalse
返回false
。
public class Sparta : Place
{
public bool MakeItReturnFalse()
{
return this is Sparta;
}
}
剧透我的解决方案:(剧透)
public class Place
{
public interface Sparta { }
}
但是为什么MakeItReturnFalse()
中的Sparta
引用{namespace}.Place.Sparta
而不是{namespace}.Sparta
呢
发布于 2017-05-23 04:02:07
但是为什么
MakeItReturnFalse()
中的Sparta
指的是{namespace}.Place.Sparta
而不是{namespace}.Sparta
?
基本上,因为这就是名称查找规则所说的。在C# 5规范中,相关的命名规则在3.8节(“命名空间和类型名”)中。
前几个项目符号-截断和注释-阅读:
如果命名空间或类型名称的形式为I
或I<A1, ..., AK>
so K=0,在我们的情况下为:
K
为零,并且T
的声明包含名为I
的类型参数,则命名空间或类型名称将引用该类型参数。NopeT
或其任何基类型包含具有名称I
和K
类型参数的嵌套可访问类型,则命名空间或类型名称引用使用给定类型参数构造的类型。Bingo!
N
,从出现命名空间或类型名的命名空间开始,继续每个封闭命名空间(如果有),并以全局命名空间结束,将评估以下步骤,直到找到实体为止:K
为零,并且I
是N
中命名空间的名称,则...[是的,将会对进行
因此,最后一个要点是,如果第一个项目符号没有找到任何内容,那么将选择Sparta
类……但是当基类Place
定义了一个接口Sparta
时,它在我们考虑Sparta
类之前就被发现了。
请注意,如果将嵌套类型Place.Sparta
设置为类而不是接口,它仍然会编译并返回false
-但编译器会发出警告,因为它知道Sparta
的实例永远不会是Place.Sparta
类的实例。同样,如果将Place.Sparta
保留为接口,但将Sparta
类设置为sealed
,您将收到一条警告,因为没有任何Sparta
实例可以实现该接口。
发布于 2017-05-23 04:02:30
当将一个名称解析为它的值时,定义的“贴近性”被用来解决歧义。无论什么定义是“最接近的”,都是所选择的定义。
接口Sparta
是在基类中定义的。类Sparta
在包含的命名空间中定义。在基类中定义的内容比在同一名称空间中定义的内容“更接近”。
发布于 2017-06-19 18:20:43
问得好!我想为那些每天不做C#的人补充一点更长的解释……因为这个问题很好地提醒了一般的名称解析问题。
以原始代码为例,通过以下方式略微修改:
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
函数定义中的类型比较,超类首先通过名称解析找到超类。
但为什么C#选择在名称解析中优先考虑超类中定义的接口?@JonSkeet知道!如果您阅读了他的答案,您将获得C#中名称解析协议的详细信息。
https://stackoverflow.com/questions/44120947
复制相似问题