Подтвердить что ты не робот

Свойства Write-Only, что точка?

Я понимаю, почему вы хотите использовать свойство только для чтения, используя следующий синтаксис:

private int _MyInt;
public int MyInt
{
  get { return _MyInt; }
}

Этот пример, вероятно, не самый лучший, потому что я думаю, что свойства только для чтения действительно сияют в сочетании с переменной readonly, но это рядом с точкой. Я не понимаю, почему использование свойства write-only использует следующий синтаксис:

private int _MyInt;
public int MyInt
{
  set { _MyInt = value; }
}

Вот как свойства только для чтения описаны в различных книгах и учебниках. Если вы установите переменную, вы концептуально прочитали бы ее в какой-то момент, по крайней мере, внутри класса, но чтобы прочитать ее даже внутри класса, который вы сделали бы это, обратившись к _MyInt, который, как я чувствую, нарушает дух инкапсуляции, свойства которого попытайтесь обеспечить соблюдение. Вместо этого, почему бы вам просто не использовать всю мощь свойства с различными правами доступа для доступа к нему как таковым:

private int _MyInt;
public int MyInt
{
  set { _MyInt = value; }
  private get { return _MyInt; }
}

Что, конечно, можно просто написать

public int MyInt { set; private get; }

Вы все еще получаете инкапсуляцию, но ограничиваете доступ к другим классам, поэтому ее по-прежнему записываете только внешние классы.

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

4b9b3361

Ответ 1

Я никогда не сталкивался с допустимым прецедентом для свойства write-only. Честно говоря, если есть допустимый прецедент для свойства записи только для записи, я думаю, что можно с уверенностью сказать, что решение плохо спроектировано.

Если вам нужна семантика "только для записи", вы должны использовать метод. Например, другой пользователь нашел пример объекта пользователя, который использует свойство write-only для установки пароля. Это плохой дизайн:

class User
{
    public string Password
    {
        set { /* password encryption here */ }
    }
}

Тьфу. Это намного лучше:

class User
{
    public void SetPassword(string password)
    {
        /* password encryption here */
    }
}

См., свойство read/write - это набор методов, которые предназначены для маскировки как поля. Они выглядят и чувствуют себя как полевые. По этой причине свойство "только для чтения" имеет смысл, потому что мы привыкли к тому, что мы можем читать поля и переменные, но не можем их изменить. Однако нет соответствующей конструкции поля или переменной, доступной для записи, но не читаемой.

Вот почему я считаю, что создание API, который использует свойства только для записи, является плохой практикой. Он противоречит интуиции тому, что я считаю главной целью синтаксиса свойств в С#.

Изменить: Больше философии... Я считаю, что классы выполняют функциональную задачу: они предоставляют контейнер для связанных данных, которые должны храниться и обрабатываться. Возьмем, например, класс User - этот класс будет содержать все части информации, которые относятся к пользователю в системе. Мы собираем все эти данные и даем им одно имя: пользователь. Таким образом мы используем классы для создания абстракций. User - это абстракция, которая позволяет нам рассуждать обо всех отдельных частях данных, которые составляют пользователь (пароль, имя, день рождения и т.д.).

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

Таким образом, это означает, что свойство write-only по определению должно создавать побочные эффекты, которые вызывающий не может видеть (потому что, если бы они могли видеть их, тогда не было бы причин, чтобы свойство было только для записи). Наилучшая конструкция на языке С# для установки значения с побочными эффектами - это метод.

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


Изменить: Вот официальная рекомендация .Net Framework Рекомендации по разработке для создания библиотек классовРуководство по дизайну элементовProperty Design

Не предоставлять свойства только для установки.

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

Ответ 2

Интересный вопрос.

После некоторого Googling, это все, что я могу найти: свойство write-only можно использовать для установки пароля для объекта User. Поскольку пароли обычно хранятся в хэшированной форме, существует (и должен быть) способ восстановить пароль после его установки.

Ответ 3

Одно использование для свойства записи только для поддержки инъекции зависимости setter.

Скажем, у меня был класс:

public class WhizbangService {
    public WhizbangProvider Provider { set; private get; }
}

WhizbangProvider не предназначен для доступа к внешнему миру. Я бы никогда не хотел взаимодействовать с service.Provider, это слишком сложно. Мне нужен класс, как WhizbangService, чтобы действовать как фасад. Но с установщиком я могу сделать что-то вроде этого:

service.Provider = new FireworksShow();
service.Start();

И сервис начинает фейерверк. Или, может быть, вы предпочтете увидеть водное и световое шоу:

service.Stop();
service.Provider = new FountainDisplay(new StringOfLights(), 20, UnitOfTime.Seconds);
service.Start();

И так далее....

Ответ 4

Общим случаем, который я вижу, является то, что вы хотите, чтобы вызывающий объект мог получить преобразованную версию вашего свойства. Например:

public int MyInt { set; }
public string MyIntAsString 
{ 
   get { return this.MyInt.ToString(); } 
}

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

ИЗМЕНИТЬ:

После прочтения примера использования Томаса реальным сценарием типа "преобразование" может быть получение зашифрованной версии свойства только для записи:

private string password;

public string ClearPassword { set { this.password = value; }
public string EncryptedPassword
{
   get { return Encrypt(password); }
}

Ответ 5

Источники, которые я прочитал, предположили, что если у вас есть ситуация, когда вы только что создали свойство write-only, вам, вероятно, стоит подумать о том, чтобы превратить его в метод. И я обычно соглашаюсь.

Ответ 6

Любая информация, которая должна поступать в одну сторону, полезна с помощью свойства write-only. Как правило, мы пишем классы для информации, чтобы выходить из нее или из нее. В случае только для записи вы должны думать о ситуациях, когда информация должна поступать только и не выходить. Обычно это относится к типу безопасности, поскольку мы не хотим, чтобы у потребителя был какой-либо доступ к поиску защищенной части информации. Пароли, номера CC и т.д.

Когда информация не защищена, например, когда мы не против, чтобы кто-либо обращался к ней, мы получаем общий шаблон get/set. 99,9% времени это то, как используются свойства. Поскольку существуют другие способы, столь же легкие, которые могут быть более надежными для достижения этого, это скорее семантическая конструкция, которая осталась для симметрии, чем что-либо. Один из редких случаев, когда что-то не было вывезено, а ваш левый: "Почему, черт возьми, они удалили это!".

Ответ 7

Причина, по которой я могу думать о моей голове, состоит в том, что в верхней части контекстного меню intellisense отображается _myInt.

Я не думаю, что доступ к _myInt вообще нарушает дух инкапсуляции; это частное поле участника класса. Любой код внутри класса СЛЕДУЕТ использовать _myInt. В конце концов, это личное.

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

И, как я уже сказал, легче захватить _myInt с intellisense, когда вы кодируете.

Ответ 8

Я уверен, что функция существует просто для symetry с переменной get-only. Поскольку Aphex в некоторой степени подразумевает, некоторые вещи не имеют смысла и только там, потому что легче оставить его, чем удалить его.

Ответ 9

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

В веб-сервисе .NET мне пришлось создать устаревший веб-сервис ASMX, поскольку URI жестко запрограммирован в аппаратном обеспечении.

Я большой поклонник использования Ninject для внедрения зависимостей, использования конструктора для удовлетворения всех зависимостей, которые может иметь класс. По большей части эти зависимости будут объявлены private readonly fieldName и назначены в конструкторе. Причина этого заключается в том, что зависимости класса не являются частью обязанностей класса; они являются зависимостями.

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

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

Используя веб-расширение Ninject, я унаследовал свой класс обслуживания от Ninject.Web.WebServiceBase и использовал внедрение свойств, помечая свойства, которые Ninject будет удовлетворять, с помощью атрибута [Inject].

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