Использование явных интерфейсов для предотвращения случайного изменения свойств в C#

StackOverflow https://stackoverflow.com/questions/1717563

  •  19-09-2019
  •  | 
  •  

Вопрос

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

В качестве примера,

 virtual public DateTime CreatedOn { get; protected set; }
 virtual public DateTime? ModifiedOn { get; protected set; }
 #region IHaveUpdateDateFields Members

 DateTime IHaveUpdateDateFields.CreatedOn
 {
    get
    {
        return this.CreatedOn;
    }
    set
    {
        this.CreatedOn = value;
    }
}

DateTime? IHaveUpdateDateFields.ModifiedOn
{
    get
    {
        return this.ModifiedOn;
    }
    set
    {
        this.ModifiedOn = value;
    }
}

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

Мои вопросы:

  1. Полагаюсь ли я на определенное поведение или мне гарантировано, что все компиляторы C# будут разрешать методы таким образом?Я не хочу обнаружить, что стандарт C# гласит, что такое разрешение метода не определено, а затем случайно получить ужасное переполнение стека, например, при сборке для Mono.
  2. Есть ли более приятный (в идеале более краткий) способ сделать это?Я мог бы иметь интерфейс, безопасный для ModelBinder, который я передаю своему контроллеру, но не похоже, что это сэкономит мне код, и я не думаю, что он обеспечит столь же прозрачный подход к минимизации случайного изменения свойств.
Это было полезно?

Решение

Это совершенно четко определено;явные реализации интерфейса имеют приоритет при использовании интерфейса, а обычное свойство вступает в силу в противном случае (в том числе внутри тела get/set).

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

DateTime IHaveUpdateDateFields.CreatedOn
{
    get { return CreatedOn; }
    set { CreatedOn = value; }
}

(обратите также внимание на то, что this является неявным и избыточным)

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

Лицензировано под: CC-BY-SA с атрибуция
Не связан с StackOverflow
scroll top