Порядок инициализации статического поля (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:
У меня есть еще вопросы по поводу примеров.
Оба примера появляются в разделе, озаглавленном " Статические конструкторы и порядок инициализации поля", однако примеры кода не показывают статический ctor - по крайней мере, тот, который я не могу легко распознать. Я ожидал, что статический ctor будет иметь то же имя, что и класс, без параметров и перед ним будет стоять ключевое слово "static". Поэтому я не вижу, как примеры относятся к заголовку раздела. Что мне здесь не хватает?
Во втором примере (нестатический) 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, так как вы знаете, что порядок объявления не важен (в этом вопросе) для членов класса.
Вышеприведенный случай просто так.