Порядок инициализации статического поля (C#) - может кто-нибудь объяснить этот фрагмент?

Я программист C++, изучающий C#. В настоящее время я читаю C#4.0 в двух словах.

Я наткнулся на это утверждение / фрагмент на странице 74:

Инициализаторы статических полей выполняются в порядке, в котором поля объявлены. Следующий пример иллюстрирует это: X инициализируется в 0, а Y инициализируется в 3.

class Foo
{
    public static int X = Y; // 0
    public static int Y = 3; // 3
}

Я не понимаю, как X может быть присвоено значение в Y, без Y, который был объявлен первым. Я что-то здесь упускаю?

Кроме того, исходя из фона C++, я склонен использовать термин ctor для конструктора - однако я еще не сталкивался с термином в C# - термин ctor также используется в мире C#?

[Редактировать]

Еще один пример на той же странице (в упомянутой ранее книге):

class Program
{
    static void Main() { Console.WriteLine (Foo.X); } // 3
}
class Foo
{
    public static Foo Instance = new Foo();
    public static int X = 3;
    Foo() { Console.WriteLine (X); } // 0
}

Книга утверждает (для примера выше):

В примере выводится 0, а затем 3, потому что инициализатор поля, который создает экземпляр Foo, выполняется до инициализации X в 3:

У меня есть еще вопросы по поводу примеров.

  1. Оба примера появляются в разделе, озаглавленном " Статические конструкторы и порядок инициализации поля", однако примеры кода не показывают статический ctor - по крайней мере, тот, который я не могу легко распознать. Я ожидал, что статический ctor будет иметь то же имя, что и класс, без параметров и перед ним будет стоять ключевое слово "static". Поэтому я не вижу, как примеры относятся к заголовку раздела. Что мне здесь не хватает?

  2. Во втором примере (нестатический) ctor выводит значение X, которому явно было присвоено значение 3 в предыдущей строке, и, тем не менее, выводится значение 0. Почему?!

6 ответов

Решение

В C# примитивные типы, такие как int принять значение по умолчанию. За intзначение по умолчанию равно 0. Это не похоже на C++, где вы должны инициализировать значение, иначе оно будет получать случайное грязное значение из памяти. Поскольку известно, что Y имеет тип int, X можно присвоить его значение по умолчанию 0.

Насколько ключевое слово ctorЯ не вижу, чтобы он использовался как программист на C#, но я знаком с этим термином. Я считаю, что он используется в нескольких местах в Visual Studio, например, в браузере объектов.

Порядок декларации не важен с точки зрения того, что доступно здесь. Это не тот случай, когда это локальные переменные, а переменная доступна только после ее объявления. То же самое верно для переменных экземпляра - и, действительно, методов, где метод, объявленный ранее в источнике, может вызвать метод, объявленный позже в источнике и т. Д.

Однако порядок объявления важен с точки зрения выполнения инициализаторов, поэтому вы получаете такое поведение. Обратите внимание, что если вы измените эти переменные на const, оба примут значение 3 - компилятор определит требуемый порядок оценки и определит, есть ли какие-либо циклы (которые могут вызвать ошибку). Затем константы будут оцениваться во время компиляции, а значения встроены непосредственно в IL.

Для получения более подробной информации о том, что является действительным и т.д., обратитесь к спецификации.

Что касается терминологии - я обычно не вижу необходимости сокращать "конструктор" до "ctor", хотя я думаю, что это будет в целом понятно. Я мог бы использовать это сокращение для имени переменной, например:

var ctor = typeof(...).GetConstructor(...);

Объявление поля не должно быть в порядке зависимости.

То есть вы можете использовать Y выше, где вы объявляете Y,

Инициализация, однако, происходит так:

  • X инициализируется первым, получает его значение из Y, который неинициализирован, и, таким образом, 0 (значение по умолчанию для int)
  • Y инициализируется в 3,

Инициализаторы фактически запускаются в конструкторе класса. Когда класс создан, все статические члены устанавливаются в ноль, тогда запускается статический конструктор. Вот почему код инициализатора может использовать Y поле для инициализации X поле.

Ваш код работает в основном так же, как:

class Foo {

  public static int X; // 0
  public static int Y; // 0

  static Foo() {
    X = Y; // 0
    Y = 3; // 3
  }

}

(Однако есть некоторые различия между классом, который имеет явный статический конструктор, и классом, который не имеет, см . Статью Джона Скита, если вы хотите копать глубже.)

Термин "ctor" не очень широко используется для "конструктора" в C#, обычно таких сокращений избегают в.NET. Вот почему идентификаторы имеют тенденцию быть длинными и описательными, а не короткими и загадочными, как StringComparison.CurrentCultureIgnoreCase а не что-то вроде str_cmp.cc_is,

Аббревиатура "ctor" используется в шаблонах в Visual Studio, набрав "ctor" и нажав tab, вы получите шаблон для конструктора.

Если вы создаете класс, такой как:

   class Foo
    {
        public static int y1 = 3;
        public static int x1 = y1;

        public static int X = Y; // 0
        public static int Y = 3; // 3


    }

и разбери его увидишь

        public static int y1 = 3;
00000021  mov         dword ptr ds:[009E9360h],3 
        public static int x1 = y1;
0000002b  mov         eax,dword ptr ds:[009E9360h] 
00000030  mov         dword ptr ds:[009E9364h],eax 

        public static int X = Y; // 0
00000035  mov         eax,dword ptr ds:[009E936Ch] 
0000003a  mov         dword ptr ds:[009E9368h],eax 
        public static int Y = 3; // 3
0000003f  mov         dword ptr ds:[009E936Ch],3 

Y не был инициализирован и его значение по умолчанию равно 0.

Сначала это кажется немного странным, но чтобы понять это, просто запомните, что это поля, а не локальные переменные. Посмотри на это:

class MyClass
{
    public void MyMethod()
    {
        var a = field1;
    }

    int field1;        
}

вы можете использовать field1 в MyMethod, так как вы знаете, что порядок объявления не важен (в этом вопросе) для членов класса.
Вышеприведенный случай просто так.

Другие вопросы по тегам