2012-06-24 3 views
4

У меня беспорядок, когда я совмещаю интерфейсы и полиморфизм.C# Интерфейсы, полиморфизм и делегаты

Скажем, у меня есть следующий интерфейс:

public Interface CanSayHello 
{ 
    String SayHello(); 
} 

Следующий класс:

public Class Person : CanSayHello 
{ 
    public String SayHello() { return "Hey, I'm a person just saying hello to you";} 
} 

И, наконец, важный класс:

public Class PoshPerson: Person 
{ 
    public String SayHello() { return "Hey, I'm too posh to say hello to you";} 
} 

Мой первый вопрос будет следующий код собрать метод PoshClass или класса Person?

public delegate String Collector(); 
event Collector CollectorEvent; 
void GetMethod(CanSayHello c){CollectorEvent += c.SayHello;} 

**GetMethod(new PoshPerson());** 

Если соберет метод из класса Person, я предполагаю, что я должен объявить метод на человеке, как виртуальные и метод в PoshPerson переопределении. Мне бы очень хотелось, чтобы две сигнатуры метода были равны. Возможно ли это каким-либо образом?

+5

Какой из них вы хотите, чтобы произошло? Если вы хотите, чтобы реализация в PoshPerson' вызывалась, почему вы хотите избежать использования методов 'virtual' /' override'? Лично я избегаю скрытия метода, когда это возможно, именно потому, что полиморфизм времени компиляции не очень интуитивно понятен. – millimoose

+2

Кстати, в руководстве по кодированию указано, что вы должны указывать интерфейсы, поставив I в качестве первой буквы. – Styxxy

+0

Должно быть довольно легко узнать, что происходит? – Michael

ответ

4

Ваш пример запускает метод Person. Если вы измените PoshPerson на PoshPerson : Person, CanSayHello (что вы, возможно, думаете, ничего не изменили бы, так как Person : CanSayHello), он запускает метод .

Я согласен с @millimoose: «Я бы избегал скрывать метод, когда это возможно, именно потому, что полиморфизм времени компиляции не очень интуитивно понятен». Я бы рекомендовал вам изменить Person.SayHello на virtual и PoshPerson.SayHello на override. Таким образом, независимо от того, знаете ли вы об этом примере как CanSayHello, Person или PoshPerson, выполняется метод текущего типа экземпляра.

+0

Кроме того, компилятор выдаст предупреждение для использования ключевого слова 'new' в в «PoshPerson», если укрытие действительно намеренно. –

1

Вы, например, запустите версию человека. См. Объяснение здесь: http://msdn.microsoft.com/en-us/library/aa664593(v=vs.71).aspx. Если вы переопределите метод в производном классе (скомпилированные рассматривает PoshPerson.SayHello, как если бы вы использовали новое, чтобы переопределить его), а базовый класс реализует интерфейс, переопределенный метод не изменяет отображение интерфейса.

Если у вас есть PoshPerson, повторно реализующий интерфейс, он будет вызывать PoshPerson's SayHello.

public class PoshPerson : Person, CanSayHello 
{ 
    public String SayHello() { return "Hey, I'm too posh to say hello to you";} 
} 

Или, если вы сделаете SayHello виртуальный в лицо, а затем заменить его в PoshPerson, он будет вызывать SayHello PoshPerson в.

+0

«Если у вас есть PoshPerson явно реализовать интерфейс», это немного вводит в заблуждение, поскольку вы не говорите о «явной реализации интерфейса», а о переопределении интерфейса. – CodesInChaos

+0

Хорошая точка @ CodeInChaos - отредактирована. – Japple

1

Я думаю, что вы хотите что-то больше вдоль линий:

public interface ITalkable 
{ 
    string SayHello(); 
    string SayGoodbye(); 
    etc... 
} 

public class Person : ITalkable 
{ 
    public virtual string SayHello() { return "Hey, I'm a person just saying hello to you";} 
    public virtual string SayGoodbye() { return "Hey, I'm a person just saying goodbye to you";} 
} 

public class PoshPerson: Person 
{ 
    public override string SayHello() { return "Hey, I'm too posh to say hello to you";} 
    public string MakePersonSayHello() { return base.SayHello(); } 

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