【问题标题】:Are nested types implicitly static?嵌套类型是隐式静态的吗?
【发布时间】:2016-02-04 13:03:11
【问题描述】:

在 C# 5.0 语言规范中它说:

请注意,常量和嵌套类型被归类为静态成员。

所以如果我写:

class A
{
   int a;

   class B
   {
       public void foo()
       {
           int j = a; // ERROR
       } 
   }
}

a 到 j 的赋值给我一个 CS0120 错误

"非静态字段、方法或 属性“成员””

所以我可以理解foo 也是隐式静态的。

但是,当我查看反编译代码和 IL 代码时,没有任何静态关键字的指示!

internal class A
{
    private class B
    {
        public void foo()
        {
        }
    }

    private int a;
}


// Nested Types
    .class nested private auto ansi beforefieldinit B
        extends [mscorlib]System.Object
    {
        // Methods
        .method public hidebysig 
            instance void foo () cil managed 
        {

        } 
        ...
    }

嵌套类型真的是所有方法都隐式静态的静态类型吗?

【问题讨论】:

  • 它说它是一个静态成员,而不是嵌套类是静态的。
  • 根本没有静态成员。 a 是实例成员,不是吗?

标签: c# inner-classes


【解决方案1】:

“嵌套类型被归类为静态成员”

嵌套类型真的是所有方法都隐式静态的静态类型吗?

否 - Type 的定义是静态成员,但类型本身不是静态的。

当它说

请注意,常量和嵌套类型被归类为静态成员。

这意味着您可以创建嵌套类的实例而无需父类的实例。

也就是说,用代码

public class Parent
{
    public class Child
    {
    }
}

要拨打new Parent.Child(),您无需先拨打new Parent()或类似的电话。


你的代码有问题

您的实际问题是嵌套类型的实例与父类型的实例是分开的 - 您的代码,

class A
{
   int a;

   class B
   {
       public void foo()
       {
           int j = a; // ERROR
       } 
   }
}

无法编译,因为在A.B.foo() 中,字段aAinstance (i.e. not static) member,并且B 没有A实例 可供参考。


如何使用嵌套类型的一种使用方式

您可以将类型嵌套视为将父级中私有成员的可访问性扩展到子级的一种方式,例如

public class Parent
{
    private int field;

    public class Child
    {
        public void WriteFieldFromParent(Parent parent)
        {
            Console.WriteLine(parent.field);
        }
    }
}

编译!您可以从Parent.Child 类中获取Parent 中的private 字段field 的值,因为它是嵌套的。请注意,我需要将Parent 的实例传递给Parent.Child.WriteFieldFromParent

事实上,MSDN page on nested types(我不知道为什么我在第一次写这个答案时没有提到它)给出了一个类似于我的例子,并说:

嵌套类型可以访问其包含类型可访问的所有成员。它可以访问包含类型的私有成员和受保护成员,包括任何继承的受保护成员。

【讨论】:

    【解决方案2】:

    您的代码将无法编译,因为a 超出范围。你应该这样写:

    class A
    {
       int a;
    
       class B
       {
           public void foo()
           {
               int j = new A().a;
           } 
       }
    }
    

    class A
    {
        static int a;
    
        class B
        {
            public void foo() {
                int j = a;
            }
        }
    }
    

    【讨论】:

    • 我个人认为你的样本是错误的。您应该在 foo 方法中提供方法参数 a 或将其传递给构造函数。创建一个新实例是无意义的。
    • 问题是关于语言规范和编译器实现,而不是如何修复代码。将字段设为静态以便能够在嵌套类中访问它是错误的。
    • @PatrickHofman 当然这不是“只是”错误。这取决于上下文和您想要实现的目标。
    猜你喜欢
    • 2018-11-20
    • 1970-01-01
    • 2020-02-16
    • 1970-01-01
    • 1970-01-01
    • 2011-06-17
    • 1970-01-01
    • 1970-01-01
    • 2018-01-13
    相关资源
    最近更新 更多