Пытаясь переопределить явную реализацию интерфейса свойства ICollection<T>.IsReadOnly
из класса Collection<T>
, я натолкнулся на некоторые документы, утверждающие, что явные реализации членов интерфейса не могут быть переопределены, поскольку они не могут иметь модификаторы, такие как virtual
или abstract
.На MSDN они даже зашли так далеко, что указали, как сделать явную реализацию элемента интерфейса доступной для наследования, создав еще один абстрактный или виртуальный член, который вызывается явной реализацией члена интерфейса.Пока проблем нет.
Но тогда мне интересно: Почему в C # возможно переопределить любой явно реализованный элемент интерфейса, просто указав интерфейс явно ?
Например, предположим, что у меня есть такой простой интерфейс со свойством и методом:
public interface IMyInterface
{
bool AlwaysFalse { get; }
bool IsTrue(bool value);
}
И класс A
, который явно реализует интерфейс, иимеет метод Test()
, который вызывает собственную реализацию члена интерфейса.
public class A : IMyInterface
{
bool IMyInterface.AlwaysFalse
{ get { return false; } }
bool IMyInterface.IsTrue(bool value)
{ return value; }
public bool Test()
{ return ((IMyInterface)this).AlwaysFalse; }
}
Как видите, ни один из четырех членов не является виртуальным или абстрактным, поэтому, когда я определяю класс B
, например, так:
public class B : A
{
public bool AlwaysFalse
{ get { return true; } }
public bool IsTrue(bool value)
{ return !value; }
}
Тогда вы ожидаете, что экземпляр B
приведёт к A
и будет вести себя как A
.И это делает:
A a = new A();
Console.WriteLine(((IMyInterface)a).AlwaysFalse); // False
Console.WriteLine(((IMyInterface)a).IsTrue(false)); // False
Console.WriteLine(a.Test()); // False
A b = new B();
Console.WriteLine(((IMyInterface)b).AlwaysFalse); // False
Console.WriteLine(((IMyInterface)b).IsTrue(false)); // False
Console.WriteLine(b.Test()); // False
Теперь приходит улов.Создайте класс C
, который является точной копией B
, за исключением одной вещи в объявлении класса:
public class C : A, IMyInterface
{ /* ... same as B ... */ }
Теперь экземпляр C
при приведении к A
не делаетведет себя как A
, но как C
:
A c = new C();
Console.WriteLine(((IMyInterface)c).AlwaysFalse); // True
Console.WriteLine(((IMyInterface)c).IsTrue(false)); // True
Console.WriteLine(c.Test()); // True
Даже метод Test()
теперь вызывает переопределенный метод в C
!Почему это?