Всегда ли в фоновом поле сгенерированного компилятором события всегда используется то же имя, что и у события? - PullRequest
9 голосов
/ 24 марта 2012

C # позволяет нам создавать собственные средства доступа к событиям .

Action _custom;
public event Action Custom
{
    add { _custom = (Action)Delegate.Combine( _custom, value ); }
    remove { _custom = (Action)Delegate.Remove( _custom, value ); }
}

Если вы не укажете их, компилятор создаст их для вас .Спецификация языка C #:

При компиляции события, подобного полю, компилятор автоматически создает хранилище для хранения делегата и создает методы доступа для события, которые добавляют или удаляют обработчики событий в поле делегата.

Декомпилированный исходный код с использованием dotPeek для простого public event Action Public; выглядит следующим образом:

  private Action Public;

  public event Action Public
  {
    add
    {
      Action action = this.Public;
      Action comparand;
      do
      {
        comparand = action;
        action = Interlocked.CompareExchange<Action>(
                     ref this.Public, comparand + value, comparand);
      }
      while (action != comparand);
    }
    remove
    {
      Action action = this.Public;
      Action comparand;
      do
      {
        comparand = action;
        action = Interlocked.CompareExchange<Action>(
                    ref this.Public, comparand - value, comparand);
      }
      while (action != comparand);
    }
  }

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

public static FieldInfo GetFieldInfo( this EventInfo eventInfo )
{
    Contract.Requires( eventInfo != null );

    return eventInfo.DeclaringType.GetField(
        eventInfo.Name,
        BindingFlags.DeclaredOnly | BindingFlags.Instance |
            BindingFlags.Public | BindingFlags.NonPublic );
}

Это работает, но поднимает вопрос: Всегда ли в гарантированном поле сгенерированного компилятором события всегда используется то же имя, что и у события?

Невозможно создать собственные средства доступа к событиям, которые получают доступ к делегату с тем же именем, используя Visual Studio.Это приводит к сообщению: «Участник с тем же именем уже объявлен». Мне интересно, можно ли сделать вывод, что любое событие, для которого недоступен вспомогательный делегат с тем же именем, является событием с пользовательскими средствами доступа.

Ответы [ 3 ]

9 голосов
/ 24 марта 2012

Всегда ли в гарантированном поле генерируемого компилятором события всегда используется то же имя, что и у события?

Джон и Марк совершенно правильно ответили "Нет".

Это недокументированная деталь реализации компилятора, явно указанная в спецификации как таковая и подлежащая изменению в любое время.

На практике это вряд ли изменится. Мы используем тот факт, что поле и событие имеют то же имя, что и самый простой способ логически связать их друг с другом в компиляторе.

Невозможно создать собственные средства доступа к событиям, которые получают доступ к делегату с тем же именем, используя Visual Studio. Это приводит к сообщению: «Участник с тем же именем уже объявлен».

Correct.

Мне интересно, могли бы вы сделать вывод, что любое событие, для которого недоступен вспомогательный делегат с тем же именем, является событием с пользовательскими средствами доступа.

Мне было бы неудобно делать такой вывод. Вы могли бы сделать такой вывод, если бы знали, что данная сборка была отправлена ​​компилятором C #. Но мы не единственная игра в городе, когда речь идет о выпуске сборок. Вы можете сделать довольно странные вещи с ILDASM.

Могу я спросить, почему ты хочешь знать это? Я согласен с Марком; если вы обращаетесь к полю через Reflection, вы, вероятно, делаете это неправильно. Вы должны иметь возможность получить доступ к полю внутри класса без проблем (потому что это просто приватное поле), и за пределами класса вам не нужно искать детали частной реализации другого класса. Особенно вопиюще использовать отражение, чтобы выполнить конечный прогон вокруг безопасности потока, навязанной аксессуарами. Эти средства доступа существуют для вашей защиты; не бегай вокруг них.

6 голосов
/ 24 марта 2012

Нет - из спецификации C # 4 (раздел 10.8.1):

Внутри класса X ссылки на Ev компилируются для ссылки на скрытое поле _ Ev. Имя « _Ev» произвольно; скрытое поле может иметь любое имя или вообще не иметь его.

Так что, хотя совместимость с исходным кодом гарантирована, нет гарантии относительно имени сгенерированного поля. (На практике я не ожидал, что это скоро изменится в компиляторе MS - но это не гарантировано, поэтому не стоит делать предположения.)

5 голосов
/ 24 марта 2012

Реализация события - это деталь реализации компилятора, и она отличается в разных компиляторах (реализация MS c # 4 отличается от реализации MS c # <4, и даже спецификации MS и ECMA расходятся). </p>

ЛичноЯ бы сказал: если вам нужно получить доступ к вспомогательному полю через отражение, вы, вероятно, неправильно используете события.

...