При попытке переопределить реализацию явного интерфейса свойства ICollection<T>.IsReadOnly
из класса Collection<T>
я столкнулся с некоторыми документами, в которых указано, что явные реализации элементов интерфейса не могут быть переопределены, поскольку они не могут иметь модификаторы, такие как virtual
или abstract
. На MSDN они даже заходят так далеко, как указывают, как сделать явную реализацию члена интерфейса доступной для наследования, создав еще один абстрактный или виртуальный элемент, который вызванный реализацией явного интерфейса. На данный момент проблем нет.
Но потом я задаюсь вопросом: Почему в С# возможно переопределить любой явно реализованный элемент интерфейса, просто указав интерфейс явно?
Например, предположим, что у меня есть простой интерфейс, подобный этому, со свойством и методом:
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
! Почему это?