Привет всем.
Интересует вопрос по следующему коду:
class Program
{
public interface II
{
void Foo();
}
public class A : II
{
public void Foo()
{
Console.WriteLine("A.Foo()");
}
}
public class B : A //, II
{
public void Foo()
{
Console.WriteLine("B.Foo()");
}
}
static void Main(string[] args)
{
B b = new B();
(b as II).Foo();
Console.ReadLine();
}
}
Есть некий интерфейс II. Есть класс (А), его реализующий, и класс, унаследованный от него (В).
В теле метода Main создается экземпляр класса В, приводится к интерфейсу и вызывается метод. На выходе получаем строку "A.Foo()". Если раскомментировать указание явного наследования класса В от интерфейса вызовется именно его метод, т.е. на экран будет выведено "В.Foo()".
Почему так?
Я имею в виду, почему не наследуется "контракт" с интерфейсом в классе В и компилятор не видит этой реализации.
PS.: виртуальные методы не предлагать (знаю, что с ними код более "красивый" и тогда все будет работать без возникновения доп-ных вопросов). Интересует сама теория без использования виртуальности при использовании интерфейсов.
Здравствуйте, Аноним, Вы писали:
А>Интересует вопрос по следующему коду:
А> class Program
А> {
А> public interface II
А> {
А> void Foo();
А> }
А> public class A : II
А> {
А> public void Foo()
А> {
А> Console.WriteLine("A.Foo()");
А> }
А> }
А> public class B : A //, II
А> {
А> public void Foo()
А> {
А> Console.WriteLine("B.Foo()");
А> }
А> }
А> static void Main(string[] args)
А> {
А> B b = new B();
А> (b as II).Foo();
А> Console.ReadLine();
А> }
А> }
А>Есть некий интерфейс II. Есть класс (А), его реализующий, и класс, унаследованный от него (В).
А>В теле метода Main создается экземпляр класса В, приводится к интерфейсу и вызывается метод. На выходе получаем строку "A.Foo()". Если раскомментировать указание явного наследования класса В от интерфейса вызовется именно его метод, т.е. на экран будет выведено "В.Foo()".
А>Почему так?
А>Я имею в виду, почему не наследуется "контракт" с интерфейсом в классе В и компилятор не видит этой реализации.
А>PS.: виртуальные методы не предлагать (знаю, что с ними код более "красивый" и тогда все будет работать без возникновения доп-ных вопросов). Интересует сама теория без использования виртуальности при использовании интерфейсов.
Потому что надо внимательно читать сообщения компилятора:
Program.cs(19,15): warning CS0108: 'Program.B.Foo()' hides inherited member 'Program.A.Foo()'. Use the new keyword if hiding was intended.
Это даже level 2. Если же переписать код так, как предлагает компилятор:
public class B : A //, II
{
public new void Foo()
{
Console.WriteLine("B.Foo()");
}
}
то становится понятно, что B::Foo никакого отношения к A::Foo не имеет, в том числе не имеет отношения и к реализации методом A::Foo интерфейса.
Сделано же так во избежание возможных нечаянных конфликтов. Например, есть метод:
public void X() {
var b = new B();
Test(b);
}
public void Test(A a) {
a.Foo(); // * Вызвался A::Foo - вызов не виртуальный
var i = (II)a;
i.Foo(); // ** А что здесь должно вызваться? A::Foo или B::Foo?
}
Так вот сейчас программист должен явно сказать, какое поведение ему нужно в точке (**). По умолчанию же (если явно не сказано другое) принимается самое очевидно и просто — вызов A::Foo, то есть того же метода, что и в (*). Если же требуется не очевидное на первый взгляд (с точки зрения использования, а не объявления!) поведение, то требуется при объявлении B явно указать, что B реализует II.