Что такое правильное CLS-совместимое соглашение об именах для защищенных полей? - PullRequest
9 голосов
/ 27 сентября 2011

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

class SomeClass
{
private int _age; //Here is OK

public int Age { get { return this._get; } }
}

Но когда я пытаюсь использовать защищенные поля, я сталкиваюсь со следующей проблемой:

class SomeClass
{
protected int _age; //Here is NOT CLS-compliant (because of _ can't be the first symbol of identifier)

public int Age { get { return this._get; } }
}

Тогда я попытался сделать так:

class SomeClass
{
protected int age; //Here is NOT CLS-compliant (because of age and Age differ only in one symbol)

public int Age { get { return this._get; } }
}

Скажите, пожалуйста, что является правильным CLS-совместимым обозначением или соглашением между разработчиками для таких случаев? Должен ли я использовать префиксы в стиле C, такие как l_age?

Ответы [ 2 ]

10 голосов
/ 27 сентября 2011

Вот более правильная версия, IMO:

private int _age;
public int Age {
    get { return this._age ; }
    protected set { this._age = value; }
}

или просто:

public int Age { get; protected set; }

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


В комментариях поднимается вопрос о событиях, например:

protected EventHandler<StateChangedEventArgs> _stateChanged;
public event EventHandler<StateChangedEventArgs> StateChanged
{
    add { lock (this.StateChanged) { this._stateChanged += value; } }
    remove { lock (this.StateChanged) { this._stateChanged -= value; } }
}

Здесь я снова утверждаю, что нет причины для защиты этого поля;событие не принадлежит к производному классу.Он может выполнять 2 разумные операции:

  1. вызывать событие
  2. подписываться / отписываться на событие

Первое должно быть сделано черезшаблон On*;последний должен просто использовать обычные средства доступа (в противном случае это нарушает блокировку).Кроме того, , даже если мы предполагаем, что lock(this.StateChanged) является опечаткой (это было бы очень, очень плохо для использования в качестве объекта блокировки -it не будет работать вообще ), обратите внимание, что в C # 4.0 встроенный компилятор имеет гораздо более эффективную стратегию блокировки (которая использует Interlocked, а не Monitor), когда вы пишете «похожее на поле» событие (т. Е. Не явно add)/ remove).Следовательно, предпочтительный подход здесь был бы:

public event EventHandler<StateChangedEventArgs> StateChanged;
protected virtual void OnStateChanged(StateChangedEventArgs args) {
    var snapshot = StateChanged; // avoid thread-race condition
    if(snapshot != null) shapshot(this, args);
}

и ... вот и все!

  • , если подкласс хочет подписаться / отписаться (не идеально, но ме) этопросто использует StateChanged += и StateChanged -=
  • , если подкласс хочет вызвать событие, он вызывает OnStateChanged(...)
  • , если подкласс хочет настроить логику события, он добавляет override до OnStateChanged

не нужно никаких не приватных полей.

2 голосов
/ 27 сентября 2011

Чтобы подтвердить ответ Марка, руководство по Field Design от Microsoft гласит:

Открытые и защищенные поля не работают должным образом и не защищены требованиями безопасности доступа к коду. Вместо использования общедоступных полей используйте закрытые поля и открывайте их через свойства.

Вероятно, поэтому вы не найдете полезного руководства по присвоению им имен (на самом деле, рекомендации по именованию просто указывают на страницу дизайна поля).

...