C # маркировка члена как "не использовать" - PullRequest
24 голосов
/ 23 января 2012
public class Demo
{
    private List<string> _items;
    private List<string> Items
    {
        get
        {
            if (_items == null)
                _items = ExpensiveOperation();

            return _items;
        }
    }
}

Другие методы в классе Demo будут иметь доступ к полю _items. Поскольку я использую свойство для отложенной загрузки элементов, я не хочу, чтобы другой разработчик по ошибке пытался использовать поле _items.

Я знаю, что есть устаревший атрибут , который я могу использовать, но это поле технически не устарело.

Есть ли лучший способ пометить участника как "не использовать"?

Ответы [ 7 ]

48 голосов
/ 23 января 2012

Хотя это не общий метод для того, что вы хотите сделать (и его нет, и, как показывают другие ответы, вам нужно доверять другим разработчикам), в этом случае вы можете создать Lazy<List<T>> ( при условии .NET 4 или более поздней версии - хотя это легко сделать бэкпорт)

class Demo {
    readonly Lazy<List<string>> _items;
    public Demo() {
        var _items = new Lazy<List<string>>( ExpensiveOperation);
    }
    List<string> Items { get { return _items.Value; }}
 }

Подход readonly / не изменяемый - это, как правило, путь для поддержки полей в любом случае.

РЕДАКТИРОВАТЬ: Основываясь на ответе @ Timwi (идите +1, если вам нравится идея), вы можете отправиться в город, и в стиле JavaScript использовать ограничение на основе возможностей , чтобы даже не разоблачить * Поле 1010 *, над ним просто закрыта операция (также включает предложение ReadOnlyCollection @Mr Disappointment):

class Demo {
    readonly Func<ReadOnlyCollection<string>> _getItems;
    public Demo() {
        var items = new Lazy<List<string>>( ExpensiveOperation);
        _getItems = () => items.Value.AsReadOnly();
    }
    ReadOnlyCollection<string> Items { get { return _getItems(); }}
 }

И так заканчивается наш дурацкий трюк с кодированием.

44 голосов
/ 23 января 2012

Переименуйте поле _items в _heyFutureDeveloperDoNotReferenceThisFieldMmmkay

12 голосов
/ 23 января 2012

Если вы установите такой атрибут, то как Items получатель получит к нему доступ, не создавая того же предупреждения / ошибки, которое генерирует то, что вы ищете?

Что вы подразумеваете под "другим"разработчик?»Если вы имеете в виду другого разработчика, работающего над этим же кодом (с вами), то достаточно простого комментария вроде:

///<summary>Do not access directly, using lazy initialization in getter.</summary>

, поскольку Visual Studio будет показывать это при наведении курсора на поле.

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

6 голосов
/ 26 января 2012

Да, есть относительно простой способ.Кто-то может подумать, что это хак, но я думаю, что это законно.Он использует правила области видимости локальной переменной для достижения желаемой конфиденциальности уровня метода:

public class Demo
{
    private readonly Func<List<string>> _getItems;

    public Demo()
    {
        List<string> items = null;
        _getItems = () =>
        {
            if (items == null)
                items = ExpensiveOperation();
            return items;
        };
    }

    public List<string> Items { get { return _getItems(); } }
}

Теперь переменная items правильно определена для метода, который ее использует.Все еще возможно получить доступ к _getItems, но это не имеет значения, потому что оно делает то же самое, что и Items.Невозможно изменить items, потому что он локальный, или _getItems, потому что он доступен только для чтения.

3 голосов
/ 25 января 2012

Я думаю, что это очень правильное занятие.К сожалению, C # не был разработан с учетом этого.Так что на практике в текущей версии языка мало что можно с этим поделать.

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

Сильно не согласен;если вы доверяете кому-либо, даже себе , , что - это когда у вас есть проблема.Лучший код не доверяет никому.Лучший код - пуленепробиваемый.Это не оставляет никоим образом для того, чтобы кто-то облажался.

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

Это личное.Доллар останавливается там.Если над частными частями класса работает более одного разработчика, они должны общаться очень хорошо.

В основном один и тот же аргумент.Да, это личное, но что с того?Почему недопустимо хорошо инкапсулировать личные данные?

PS Я предложил соответствующий (но не совсем прямой) практический подход для обеспечения лучшей пуленепробиваемости кода в C # но я не думаю, что многие это видели.Итак, вот так :) Я хотел бы увидеть практический подход для инкапсуляции частных членов.

1 голос
/ 23 января 2012

абсолютно ничего не делать.

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

С частным полем нет никаких причин, по которым мы бы сделали такое предположение.

Кроме того, если я приду в этот класс в качестве нового разработчика в команде, я не знаю, что делает _items. Что я собираюсь делать с этим? Я не могу выполнить какую-либо значимую работу, пока не посмотрю, что с ней делает существующий код. И я собираюсь увидеть, что это поле поддержки для лениво загруженного свойства. Тем более, если есть хоть немного документирования комментариев.

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

0 голосов
/ 23 января 2012

Как насчет

private Dictionary<String,Object> PandorasCoochie = new Dictionary<String,Object>()

Затем добавьте туда своих неприкосновенных сторонников собственности.

...