2010-08-18 3 views
21

Я хочу, чтобы это сделать:Наследование интерфейса: возможно ли расширение возможностей?

interface IBase 
{ 
    string Property1 { get; } 
} 

interface IInherited : IBase 
{ 
    string Property1 { get; set; } 
} 

Так что IInherited будет иметь унаследовал свойство Property1 с дополнительными функциями, чтобы позволить set.

Возможно ли это? Что такое синтаксис?

EDIT: обратите внимание, что слово «унаследовано» выделено жирным шрифтом. Я спрашиваю конкретно о наследовании собственности, а не о том, чтобы скрывать ее за новой.

+3

Я думаю, что существует путаница между наследованием классов и наследованием интерфейсов. Один интерфейс на самом деле не наследует другого, в том же классе наследует другой. Весь ваш код говорит о том, что IInherited также реализует IBase. Код в порядке, он просто вызывает предупреждение компилятора, потому что вы меняете подпись Property1 в интерфейсе. Вы можете очистить это с помощью нового. –

+0

Как уже отмечалось многими другими, этот синтаксис невозможен, но я чувствую, что это должно быть. Если вы используете Reflection on Property1, будет метод Property1_get и метод Property1_set, поэтому логически кажется, что вы должны реализовать их отдельно. И отсутствие возможности сделать это определенно заставляет меня иногда дублировать код (или мириться с новым ключевым словом). – cedd

ответ

24

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

Уверен, вы могли бы сказать, что IInherited «наследуется от» IBase; но что это на самом деле означает? Это интерфейсы; они устанавливают кодовые контракты. Скрывая свойство IBase.Property1 с new string Property1 { get; set; }, вы не скрываете никаких функций. Таким образом, традиционная причина, по которой многие разработчики считают, что скрывать свою «плохую» вещь, - что она нарушает полиморфизм, в данном случае не имеет значения.

Задайте себе вопрос: что действительно Вопросы Что касается интерфейсов? Они обеспечивают гарантию ответа на определенные вызовы методов, не так ли?

Таким образом, учитывая следующие два интерфейса:

interface IBase 
{ 
    string Property1 { get; } 
} 

interface IInherited : IBase 
{ 
    new string Property1 { set; } 
} 
  1. Если объект реализует IBase, вы можете прочитать его свойство Property1.
  2. Если объект реализует IInherited, вы можете прочитать его свойство Property1 (как и с реализацией IBase), и вы также можете написать ему.

Опять же, здесь действительно ничего проблемного.

+4

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

+0

@Merlyn, согласился. Удалив 2-го оператора get, это больше не будет нарушать LSP. –

+1

Ваш код объявляет два * разных * геттера для этого свойства. В 'IInherited' вы, вероятно, хотите объявить только' new string Property1 {set; } '. Класс, который реализует 'IInherited', может иметь свойство с геттером и сеттером, и он будет реализовывать оба интерфейса. – Timwi

1

Ваш код должен работать в любом случае ... он просто создает предупреждение об ущемлении из-за скрытия Property1. Чтобы удалить это предупреждение знак property1 в IInherited с новым префиксом

0

Вы можете отметить свойство с «новым» ключевым словом, или вы можете пропустить наследование:

public interface IBase 
{ 
    string Property1 { get; } 
} 

public interface IInherited : IBase 
{ 
    new string Property1 { get; set; } 
} 

Или:

public interface IBase 
{ 
    string Property1 { get; } 
} 

public interface IInherited 
{ 
    string Property1 { get; set; } 
} 

Так или иначе, это должно работать:

public class SomeClass : IInherited, IBase 
{ 
    public string Property1 
    { 
     get 
     { 
      // ... 
     } 
     set 
     { 
      // ... 
     } 
    } 
} 

вы можете трудно подумать, прежде чем сделать цепочка наследования для ваших интерфейсов. Кто будет видеть, какой интерфейс? Вам нужно было бросить на IInherited при передаче IBase? Если да, можете ли вы гарантировать, что вы можете сделать это приведение (если вы разрешаете классы, созданные пользователем, тогда ответ отрицательный)? Такое наследование может действительно повредить (повтор) юзабилити, если вы не будете осторожны.

1

Не указано, нет. У вас есть два варианта:

public interface IBase 
{ 
    string Property1 { get; } 
} 

public interface IInherited : IBase 
{ 
    void SetProperty1(string value); 
} 

Или вы можете просто убить компилятор предупреждение с new ключевого слова:

public interface IBase 
{ 
    string Property1 { get; } 
} 

public interface IInherited : IBase 
{ 
    new string Property1 { get; set; } 
} 

Если вы не реализуете IInherited.Property1 явно, IBase будет связываться с вашей реализации устанавливаемое автоматически.

+0

В реализации есть только 1 свойство, называемое Property1. Если вы получаете доступ к реализации посредством ссылки на IInherited, вы можете вызвать getter и setter, и если вы получите доступ к нему через IBase, вы можете только вызвать getter. Но это обязательное поведение, не так ли? –

+0

Да, это то, чего я хочу. Но мне, вероятно, придется идти с методами getter/setter, так как кажется, что этого не может быть сделано ... – Malki

+0

Это можно сделать, точно так же, как вы это делаете ... вы получаете ошибку компилятора? Какая ошибка? –

1

К сожалению, нет - свойства не могут быть расширены как таковые. Тем не менее, вы можете просто скрыть свойство с помощью нового:

interface IInherited : IBase 
{ 
    // The new is actually unnecessary (you get warnings though), hiding is automatic 
    new string Property1 { get; set; } 
} 

Или, вы можете сделать свои собственные методы получения и установки, которые могут быть переопределены (хорошо «ола Java стиль):

interface IBase 
{ 
    string GetProperty1(); 
} 
interface IInherited : IBase 
{ 
    void SetProperty1(string str); 
} 

Свойства фактически преобразуются в методы getter и setter компилятором.

1

Скрытие члена нарушает Принцип замены Лискова и в значительной степени просто не должно быть сделано. Скрывая этого члена, вы вводите очень сложную задачу поиска ошибки, так как будут возникать два разных результата, независимо от того, вы используете объект IBase1 или передаете его в IBase.

http://en.wikipedia.org/wiki/Liskov_substitution_principle

+2

-1. Это не скрывается в традиционном смысле, так как интерфейсы в любом случае не поддерживают полиморфизм. –

+1

Adam: Я думаю, что Крис прав, IFF мы размещаем его комментарий в контексте явно реализованных интерфейсов с различными реализациями. –

+2

Класс, который реализует IInherited, может быть отличен как IBase с меньшими правами на его модификацию, он не переопределяет реализацию метода, поскольку получатель будет возвращать то же самое (как общий доступ к двум интерфейсам «реализация геттера») –

Смежные вопросы