Поиск

Чем занимается компилятор на самом деле

Итак, как же компилятор позволяет вызывать метод с помощью стандартного синтаксиса объект.поле! И откуда берется переменная value"! Чтобы ответить на эти вопросы, взглянем на MSIL-код, сгенерированный компилятором. Сначала рассмотрим метод-получатель свойства. В следующем примере определен такой метод-получатель:

class Address
{
protected string city; protected string zipCode;
public string ZipCode {
get {
return zipCode;
} >
>

Взглянув на MSIL, получившийся из этого метода, вы увидите, что компилятор создал метод-аксессор getJZipCode, как показано ниже:

.method public hidebysig specialname
instance string. get_ZipCode() cil managed
{
// размер 11 (Oxb)
.maxstack 1
.locals ([0] string _Vb_t_SYS-PAGE-CONTENT000003SYS-PAGE-CONTENT000000)
IL.OOOO: ldarg.0
IL_0001: Idfld string Address::zipCode
IL_0006: stloc.O
IL_0007: br.s IL_0009
IL_0009: ldloo.0
ILJWOa: ret } // конец метода Address::get_ZipCode

Вы можете сообщить имя метода-аксессора, поскольку компилятор добавляет к имени префикс get_ (в случае метода-получателя) или set_

(в случае метода-установщика). В результате следующий код разрешается как вызов get__ZipCode:

String str = addr.ZipCode; // вызывает Address::get_ZipCode
Поэтому у вас может быть соблазн самим явно вызвать метод-аксессор:
String str = addr.get_ZipCode; // *"ОШИБКА - компилироваться не будет

Однако в этом случае код не будет скомпилирован, так как явно вызывать внутренний метод MSIL недопустимо.

Ответ на наш вопрос — как компилятор позволяет использовать стандартный синтаксис объект.поле для вызова метода? — в том, что при разборе синтаксиса свойства на С# компилятор на самом деле генерирует для нас соответствующие методы-получатели и установщики, поэтому в случае свойства Address.ZipCode компилятор генерирует MSIL, содержащий методы get_ZipCode и setJZipCode.
А теперь посмотрим на сгенерированный метод-установщик. В классе Address вы видели следующее:

public string ZipCode
{ /'"
set {
// Сверить почтовый индекс с базой данных.
zipCode = value;
// обновить город на основе проверенного zipCode. } }

В этом коде не объявлена переменная value, но мы все же можем использовать ее для хранения значения, переданного вызывающим кодом, и для установки защищенного поля zipCode. Генерируя MSIL для метода-установщика, компилятор С# вводит эту переменную как аргумент метода set_ZipCode. В сгенерированном MSIL этот метод принимает как аргумент строковую переменную:

.method public hidebysig specialname instance void
set_ZipCode(string 'value') cil managed {
// размер кода 8 (0x8)
.maxstack 8
ILJWOO: ldarg.0
IL_0001: ldarg.1
IL_0002: stfld string Address::zipCode IL_0007: ret } // конец метода Address::set_ZipCode

Даже если вы не найдете этого метода в исходном коде на С#, при установке свойства ZipCode [например, так: addr.ZipCode(" 12345")}, оно разрешается в MSIL-вызов метода Address ::set_ZipCode(" 12345"). Как и в случае метода getJZipCode, попытка прямого вызова этого метода на С# приводит к ошибке.