При использовании свойства C # должно ли get или setable его массировать базовые данные (если есть необходимость)? - PullRequest
3 голосов
/ 04 июня 2010

В кодовой базе, которую я поддерживал, я нашел этот точный класс, вставленный ниже. В свойстве logPath gets выполняет некоторую работу. Я бы подумал, что лучше сделать работу в set - так будет сделано только один раз. Однако, отчасти потому, что так написан класс, отчасти потому, что это свойство, отображаемое в xml, и отчасти потому, что я боюсь, что могу что-то упустить в отладчике, у меня есть сомнения.

Кроме того, если элемент никогда не существовал в xml, и он оказался необязательным, тогда я думаю, что получу ноль для значения. Я мог бы на самом деле хотеть провести различие между отсутствием элемента и получением пустого значения. Я полагаю, что у меня может быть личный член bool, который может помочь мне обнаружить это - это было бы аргументом для работы в set, а не get. Итак, в настоящее время оптимизаторы кода усердно работают, поэтому производительность редко вызывает серьезную озабоченность. Это скорее «разобраться с этим один раз и не думать об этом позже». Это только один пример, и свойства часто делают некоторые массажи.

Не могли бы вы сказать, что всегда лучше работать в set? В get? Это зависит? Смешанный стиль не будет вас беспокоить, пока он работает?

Спасибо.

namespace MyNamespace
{
    using System;
    using System.Xml.Serialization;

    /// <summary>
    /// The LoggingListener class encapsulates the "logListener" 
    ///      element of config file, and puts the "logPath" 
    ///      attribute in a file path string.
    /// </summary>
    public class LoggingListener
    {
        private string logPathValue;

        /// <summary>
        /// Gets or sets the LOCAL file path to a log file 
        /// which will be written during operation of the Updater.
        /// </summary>
        [XmlAttribute("logPath")]
        public string LogPath
        {
            get
            {
                return this.logPathValue == null ? 
                         String.Empty : this.logPathValue;
            }

            set
            {
                this.logPathValue = value;
            }
        }
    }
}

РЕДАКТИРОВАТЬ: В данном примере ... если файл журнала не существует, то регистрация не должна проводиться.

Ответы [ 4 ]

4 голосов
/ 04 июня 2010

Я бы предпочел последовательность. Но в таких случаях это часто не имеет значения. Я уверен, что первоначальный замысел разработчика состоял в том, чтобы избежать приводящей в бешенство ошибки NullReferenceException, возникающей в результате попытки доступа к свойству LogPath какого-либо объекта LoggingListener - в этом случае, вероятно, наиболее разумно было бы поставить null отметьте get (поскольку именно там было выброшено исключение).

В целом, я бы согласился с вами, что, возможно, имеет смысл поместить его в set - но тогда нет никакой гарантии, что LogPath не будет никогда вернет null поскольку закрытый член мог быть установлен на null из класса, или, возможно, он никогда не был установлен вообще (как указал Кевин).

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

public class LoggingListener {
    private readonly string _logPath;

    public LoggingListener(string logPath) {
        _logPath = logPath ?? string.Empty;
    }

    public string LogPath {
        get { return _logPath; }
    }
}

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

3 голосов
/ 04 июня 2010

Мне лично не нравится, когда свойство меняет присвоенное значение в get или set accessor. Изменяет ожидаемое поведение свойства:

var value = null;
var listener = new LoggingListener();
listener.LogPath = value;
if(listener.LogPath != value)
{
    // how could we get here?
}

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

Если нет способа предотвратить присвоение null, чем я бы предпочел обработать этот случай в set accessor.

2 голосов
/ 05 июня 2010

С геттерами и сеттерами я следую нескольким правилам:

  1. Нет побочных эффектов - не изменяйте 'B', когда вы вводите значение в 'A'
  2. То, что я положил в 'A', получено из 'A', если вам нужно изменить 'A', откройте новое свойство только для чтения
  3. Если вам не нравится мое значение для 'A', скажите мне сейчас, не позже, когда я вызову метод
  4. За пределами модели данных, не принимать и не возвращать ноль

Для вашего примера я предпочитаю видеть следующее:

public class LoggingListener
{
    private string logPathValue = String.Empty;

    [XmlAttribute("logPath")]
    public string LogPath
    {
        get { return logPathValue; }
        set
        {
            if(value == null) throw new ArgumentNullException();
            this.logPathValue = value;
        }
    }
}

Тем не менее, для меня ясно, почему вы спрашиваете, это действительно о поведении "XmlAttribute" и XmlSerializer. Вы можете использовать « DefaultValueAttribute » из пространства имен ComponentModel, или использовать XSD для предоставления значений по умолчанию, или предоставить новое свойство и / или метод. Вы также можете попробовать создать интерфейс для разделения проблем, например:

public class LoggingListener : ILogListenerSettings
{
    private string logPathValue;

    [XmlAttribute("logPath")]
    public string LogPath
    {
        get { return logPathValue; }
        set { logPathValue = value; }
    }

    string ILogListenerSettings.FullLogPath
    {
        get
        {
            string path = logPathValue;
            if(String.IsNullOrEmpty(path))
                path = Environment.CurrentDirectory;
            path = Path.GetFullPath(path);
            Directory.Create(path);
            return path;
        }
    }
}
0 голосов
/ 04 июня 2010

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

public class LoggingListener
{
    private string logPathValue = string.Empty;
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...