Передача по значению против передачи по ссылке с полиморфизмом

В следующем коде показан пример передачи по ссылке с использованием ключевого слова ref.

class Program
{
    static void Main(string[] args)
    {
        int c1 = 10;
        ClassC c2 = new ClassC(10);
        ClassA a = new ClassB();

        a.MethodA(ref c1); Console.WriteLine(c1);
        a.MethodB(ref c2); Console.WriteLine(c2.getC());

        Console.Read();
    }
}

class ClassA //base class
{
    public virtual void MethodA(ref int c1)
    {
        c1 = c1 + 5;
    }
    public virtual void MethodB(ref ClassC c2)
    {
        c2.setC(c2.getC() + 5);
    }
}

class ClassB : ClassA  //ssubclass
{
    public override void MethodA(ref int c1)
    {
        c1 = c1 - 5;
    }
    public void MethodB(ref ClassC c2)
    {
        c2.setC(c2.getC() - 5);
    }
}


class ClassC //just a class with a variable c with get/set methods
{
    protected int c;
    public ClassC(int CValue) { c = CValue; }
    public void setC(int cnew) { this.c = cnew; }
    public int getC() { return c; }
}

Если нет ключевого слова ref, оно будет передано по значению, и я получу результат 10 и 15.

Однако с ключевым словом ref я фактически получаю результат 5 и 15! Почему код без ref указывает на метод в classA, а код со ref указывает на метод в classB? Я предполагаю, что это как-то связано с полиморфизмом — classB наследует class A, но как вы это объясните?


person BOOnZ    schedule 27.04.2013    source источник
comment
Прочтите предупреждения вашего компилятора; они говорят вам, что здесь происходит.   -  person Eric Lippert    schedule 28.04.2013


Ответы (3)


ClassB.MethodB не переопределяет ClassA.MethodB, и вы вызываете MethodB из ссылки ClassA.

если вы хотите, чтобы ClassB.MethodB вызывался в этом случае, вам нужно будет добавить ключевое слово переопределения, если .net не идентифицирует его как другой метод.

person fbiagi    schedule 27.04.2013

Почему код без ref указывает на метод в классе A, а код с ref указывает на метод в классе B?

Ваш код вызывает ClassB.MethodA и ClassA.MethodB. Всегда. Сделки с ref нет...

person tukaef    schedule 27.04.2013

Это не вопрос ref или нет.

У вас есть ClassA a = new ClassB();, то есть a имеет тип времени компиляции ClassA, но тип времени выполнения является более производным, а именно ClassB.

1: Вы вызываете метод virtual MethodA. Этот метод переопределяется ClassB, поэтому из-за виртуальной диспетчеризации используется переопределенная реализация.

2: Вы вызываете метод virtual MethodB. Этот метод (унаследован, но) не переопределен. Поэтому используется его "оригинальная" (и единственная) реализация в ClassA. Как я уже сказал, ClassA является типом времени компиляции a. Тот факт, что ClassB вводит новый метод с тем же именем и сигнатурой, не имеет значения. Может быть, вы по ошибке пропустили ключевое слово override? Компилятор выдал вам предупреждение о сокрытии метода.

Всегда избегайте введения нового члена (в производном классе), который скрывает существующий член, унаследованный от базового класса. Вместо этого попробуйте использовать новое имя (идентификатор) или новую подпись, которая не конфликтует с существующим элементом. Или, может быть, вообще не происходит от базового класса.

person Jeppe Stig Nielsen    schedule 27.04.2013