Есть ли причина скрывать наследуемые элементы в интерфейсе? - PullRequest
13 голосов
/ 26 августа 2010

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

Есть ли практическая причина скрывать элементы в интерфейсах, которые реализуют другие интерфейсы? Например, рассмотрим пример ниже. IChildInterface реализует IParentInterface и скрывает PropertyA.

interface IParentInterface
{
    string Name { get; set; }
    int PropertyA { get; set; }
    int PropertyB { get; set; }
}

interface IChildInterface : IParentInterface
{
    int PropertyA { get; set; }
    int PropertyC { get; set; }
}

Ответы [ 5 ]

23 голосов
/ 26 августа 2010

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

Конечно. Тот факт, что сама BCL использует этот шаблон, свидетельствует о его практичности. Например:

interface IEnumerable 
{ 
    IEnumerator GetEnumerator();
}
interface IEnumerable<T> : IEnumerable
{
    new IEnumerator<T> GetEnumerator();
}

Разработчики IEnumerable<T> хотели быть обратно совместимыми с IEnumerable, но также хотели, чтобы каждое использование GetEnumerator в универсальном интерфейсе называлось универсальной версией. Сокрытие является подходящим механизмом в этом случае.

Дополнительное обсуждение тонких моментов, касающихся сокрытия методов, см. В

http://blogs.msdn.com/b/ericlippert/archive/2008/05/21/method-hiding-apologia.aspx

7 голосов
/ 26 августа 2010

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

public interface IBase
{
   int MyProperty { get; }
}

public interface IDerive : IBase
{
    // you need to specify the getter here too
    new int MyProperty { get; set; }
}
2 голосов
/ 26 августа 2010

Интерфейсы не могут полностью скрыть родительские интерфейсы, но реализующий класс может, что может быть полезно.

Рассмотрим класс MyStringList, который является списком только для чтения, который реализует IList<string>.Для простоты мы сделаем это простым переходом: некоторые члены довольно бессмысленны, поэтому мы можем сделать следующее:

//implement this one implicitly, as it's useful.
public int Count
{
  return _list.Count;
}
//do a half-and-half on the indexer
public string this[int index]
{
  get
  {
    return _list[index];
  }
}
string IList<string>.this[int index]
{
  get
  {
    return this[index];
  }
  set
  {
    throw new NotSupportedException("Collection is read-only.");
  }
}
//hide some pointless ones.
bool ICollection<string>.IsReadOnly
{
  get
  {
    return true;
  }
}
void IList<string>.Insert(int index, string item)
{
  throw new NotSupportedException("Collection is read-only.");
}
void IList<string>.RemoveAt(int index)
{
  throw new NotSupportedException("Collection is read-only.");
}
void ICollection<string>.Add(string item)
{
  throw new NotSupportedException("Collection is read-only.");
}
void ICollection<string>.Clear()
{
  throw new NotSupportedException("Collection is read-only.");
}
bool ICollection<string>.Remove(string item)
{
  throw new NotSupportedException("Collection is read-only.");
}

Кто-то, имеющий дело с интерфейсом от MyStringList до IList<string>должен иметь возможность вызывать этих бессмысленных членов, но для этого не нужно, чтобы кто-то имел дело с MyStringList.

Теперь, когда это возможно для класса, интерфейс может навязать такое влияние наКласс по имени совпадает с родительским интерфейсом.Пример класса IEnumberable<T>, где GetEnumerator() совпадает с IEnumerable, от которого он наследуется.Следовательно, класс может неявно реализовывать только один и должен скрывать другой или оба (так как один всегда может привести результат (IEnumerator<T>) к типу результата другого (IEnumerator), тогда наиболее разумным является поведениекак правило, для неявной реализации версии IEnumberable<T> и явной реализации версии IEnumerable (обычно возвращая результат другого).

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

1 голос
/ 26 августа 2010

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

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

См. Также: Была ли когда-нибудь ситуация, когда производный класс должен скрываться ...?

0 голосов
/ 26 августа 2010

Полагаю, если вы собираетесь явно реализовать IChildInterface, может возникнуть ситуация, когда вы захотите скрыть PropertyA (может быть?)

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...