Я понимаю, как работать с интерфейсами и явной реализацией интерфейса в C #, но мне было интересно, считается ли плохой формой прятать некоторых членов, которые не будут использоваться часто. Например:
public interface IMyInterface
{
int SomeValue { get; set; }
int AnotherValue { get; set; }
bool SomeFlag { get; set; }
event EventHandler SomeValueChanged;
event EventHandler AnotherValueChanged;
event EventHandler SomeFlagChanged;
}
Я заранее знаю, что эти события, хотя и полезны, очень редко используются. Таким образом, я подумал, что имеет смысл скрывать их от реализующего класса через явную реализацию, чтобы избежать беспорядка в IntelliSense.
c#
interfaces
implementations
Кайл Баран
источник
источник
Ответы:
Да, это вообще плохая форма.
Если ваш IntelliSense слишком перегружен, ваш класс слишком велик. Если ваш класс слишком большой, он, вероятно, делает слишком много вещей и / или плохо спроектирован.
Исправьте свою проблему, а не свой симптом.
источник
Используйте функцию для чего она была предназначена. Сокращение беспорядка пространства имен не является одним из них.
Законные причины не о «сокрытии» или организации, а о разрешении двусмысленности и специализации. Если вы реализуете два интерфейса, которые определяют «Foo», семантика для Foo может отличаться. На самом деле не лучший способ решить эту проблему, за исключением явных интерфейсов. Альтернативой является запрещение реализации перекрывающихся интерфейсов или объявление о том, что интерфейсы не могут ассоциировать семантику (что в любом случае является просто концептуальной вещью). Оба - плохие альтернативы. Иногда практичность превосходит элегантность.
Некоторые авторы / эксперты считают это существом (методы на самом деле не являются частью объектной модели типа). Но, как и все функции, где-то кому-то это нужно
Опять же, я бы не стал использовать это для сокрытия или организации. Есть способы скрыть участников от intellisense.
источник
IDisposable.Dispose
что-то происходит, но им присваивается другое имя, напримерClose
, я считаю, что это вполне разумно для класса, в контракте которого явным образом отказывается утверждать, что код может создавать и оставлять экземпляры без вызоваDispose
использования явной реализации интерфейса для определитьIDisposable.Dispose
метод, который ничего не делает.Я мог бы быть признаком грязного кода, но иногда реальный мир грязный. Одним из примеров .NET Framework является ReadOnlyColection, который скрывает мутирующий сеттер [], Add и Set.
IE ReadOnlyCollection реализует IList <T>. Смотрите также мой вопрос к SO несколько лет назад, когда я обдумывал это.
источник
ConcurrentDictionary
, что реализует различные членыIDictionary<T>
явно, так что потребителиConcurrentDictionary
A) не будут вызывать их напрямую, а B) могут использовать методы, которые требуют реализации,IDictionary<T>
если это абсолютно необходимо. Например, пользователямConcurrentDictionary<T>
следует звонить,TryAdd
а неAdd
избегать ненужных исключений.Add
явно также уменьшает беспорядок.TryAdd
может делать все, чтоAdd
может (Add
реализовано как вызовTryAdd
, так что предоставление обоих будет избыточным). ОднакоTryAdd
обязательно имеет другое имя / сигнатуру, поэтому невозможно реализоватьIDictionary
без этой избыточности. Явная реализация решает эту проблему чисто.Это хорошо, когда член бессмыслен в контексте. Например, если вы создаете коллекцию только для чтения, которая реализуется
IList<T>
путем делегирования внутреннему объекту_wrapped
тогда у вас может быть что-то вроде:Здесь у нас есть четыре разных случая.
public T this[int index]
определяется нашим классом, а не интерфейсом, и, следовательно, конечно, не является явной реализацией, хотя обратите внимание, что это действительно похоже на чтение-записьT this[int index]
определенное в интерфейсе, но только для чтения.T IList<T>.this[int index]
является явным, потому что одна его часть (получатель) идеально соответствует указанному выше свойству, а другая часть всегда будет выдавать исключение. Хотя это жизненно важно для тех, кто обращается к экземпляру этого класса через интерфейс, он не имеет смысла для тех, кто использует его через переменную типа класса.Точно так же, потому что
bool ICollection<T>.IsReadOnly
всегда собирается возвращать true, это совершенно бессмысленно для кода, который написан против типа класса, но может быть жизненно важным для этого, используя его через тип интерфейса, и поэтому мы реализуем его явно.Наоборот,
public int Count
не реализован явно, потому что потенциально может быть полезен для кого-то, использующего экземпляр через его собственный тип.Но с вашим «очень редко используемым» случаем я бы очень сильно склонялся к тому, чтобы не использовать явную реализацию.
В тех случаях, когда я рекомендую использовать явную реализацию, вызов метода через переменную типа класса будет либо ошибкой (попытка использовать индексированный установщик), либо бессмысленной (проверка значения, которое всегда будет одним и тем же), поэтому при сокрытии их вы защищаете пользователя от ошибочного или неоптимального кода. Это существенно отличается от кода, который, по вашему мнению, редко используется. Для этого я мог бы рассмотреть возможность использования
EditorBrowsable
атрибута, чтобы скрыть член от intellisense, хотя даже это было бы утомительно; У людей уже есть свое программное обеспечение для фильтрации того, что им не интересно.источник
IsReadOnly
свойство?