Подтип C # приведен к супертипу, но все еще нужен метод подтипа - PullRequest
0 голосов
/ 05 января 2012

Мне интересно, возможно ли следующее:

class A
{
    public int SomeMethod()
    {
        return 1;
    }
}

class B : A
{
    public override int SomeMethod()
    {
        return 3;
    }
}

class DrivingClass
{
    public static void Main()
    {
        B classB = new B();
        A classA = (A)classB;
        Assert.IsEqual(3, classA.SomeMethod()); 

    }
}

Это, конечно, не дает ожидаемого значения 3, но фактическое значение равно 1. Есть ли способ (без повторной передачи его обратно к B) для classA.SomeMethod () вызвать переопределенную версию, поскольку она начиналась как B (хотя я предполагаю, что это знание потерянный раз кастом).

UPDATE: Класс А уже написан и для всех намерений и целей не может быть отредактирован. Я могу управлять только классом B. Зная, что класс B будет приведен к типу A, я просто хочу, чтобы моя реализация использовалась, когда SomeMethod () вызывается для моего tytypeasted B.

Ответы [ 4 ]

3 голосов
/ 05 января 2012

SomeMethod должен быть объявлен как виртуальный в A, чтобы успешно переопределить его в B.

 public virtual int SomeMethod() // in A
 public override int SomeMethod() // in B

С этим правильно на месте

 A a = new B();
 int value = a.SomeMethod(); 
 Debug.Assert(value == 3); // succeeds

Если у вас вместо есть

 public int SomeMethod() // in A
 public new int SomeMethod() // in B, or just 
 public int SomeMethod() // in B

Тогда приведенное выше утверждение не выполняется.Метод в B скрывает базовый метод, но только через ссылку B.Работая по ссылке A, вы получаете базовое поведение.

 A a = new B();
 int value = a.SomeMethod(); // gets 1 from A, not 3 from B

ОБНОВЛЕНИЕ: Класс A уже написан и для всех целей и задач не может быть отредактирован.Я могу управлять только классом B. Зная, что класс B будет приведен к типу A, я просто хочу, чтобы моя реализация использовалась, когда SomeMethod () вызывается для моего tytypeasted B.

Методы не являются виртуальнымипо умолчанию в C #.Если авторы A не разработали его с учетом расширяемости (по крайней мере, до переопределения SomeMethod), вы не сможете заменить или переопределить это поведение на B, когда оно рассматривается как A.Однако, , если вы в состоянии контролировать приведение , или, скорее, зависимость кода, вы, возможно, можете инвертировать его так, чтобы A фактически придерживался контракта B, а не наоборот.Рассмотрим, например, шаблон адаптера .

interface IB
{
    int SomeMethod();
}

class B : IB
{
    public int SomeMethod() { return 3; }
}

class ABAdapter : IB
{
    private A a; 
    public ABAdapter(A a) { this.a = a; }
    public int SomeMethod() { return a.SomeMethod(); } 
}

В этом примере вы использовали адаптер для шаблона, чтобы A фактически выполнял контракт B через интерфейс IB.Таким образом, код, который когда-то мог зависеть от A или B, теперь может зависеть от IB.ABAdapter просто делегирует реализацию A.

public void DoSomething(IB ib) // given 

A a = new A();
DoSomething(new ABAdapter(a)); // invoke with A
DoSomething(new B()); // invoke with B
1 голос
/ 05 января 2012

Вы не объявили SomeMethod виртуальным в A, так что это явно не ваш реальный код (иначе B не может его переопределить), но когда вы вносите это изменение, оно will return 3. Если этого не произойдет, полиморфизм будет полностью нарушен.

Теперь, другое изменение, которое мы могли бы внести в код, который вы разместили, находится в B. Если вы используете:

public new int SomeMethod()
{
    return 3;
}

Тогда ваше утверждение потерпит неудачу - потому что оно вызовет A.SomeMethod(), который затенен или скрыт от B.SomeMethod(),не переопределеноПо сути, если вам нужно полиморфное поведение, вам нужно использовать override, и это должно быть в виртуальном методе.

0 голосов
/ 05 января 2012

Учитывая ваше изменение о том, что вы не можете переопределить класс A, я боюсь, что вам более или менее не повезло.

Возможно получить B из A, а затемобъявите new int SomeMethod(), но вы не сможете вызвать этот метод со ссылкой A.Вы можете использовать проверку типа во время выполнения:

int CallSomeMethod(A obj)
{
    var b = obj as B;
    return b == null ? obj.SomeMethod() : b.SomeMethod();
}
0 голосов
/ 05 января 2012

Предлагаю прочитать по теме здесь В статье приведены примеры кода:

class A
{
   public void F() { Console.WriteLine("A.F"); }
   public virtual void G() { Console.WriteLine("A.G"); }
}
class B: A
{
   new public void F() { Console.WriteLine("B.F"); }
   public override void G() { Console.WriteLine("B.G"); }
}
class Test
{
   static void Main() {
      B b = new B();
      A a = b;
      a.F(); //prints A.F
      b.F(); //prints B.F
      a.G(); //prints B.G (due to virtual method override)
      b.G(); //prints B.G
   }
}
...