Warning: file_get_contents(/data/phpspider/zhask/data//catemap/2/csharp/301.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
C# 这是斯巴达,还是?_C#_Inheritance_Types_Namespaces - Fatal编程技术网

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
return
false

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我想说添加这样一个嵌套类是一个改变,在这个改变中