C # Унаследованные переменные-члены ведут себя непредвиденно - PullRequest
0 голосов
/ 19 мая 2010

Если у меня есть такой класс:

class A {
    public string fe = "A";
}

И класс, который наследует от него, вот так:

class B : A {
    public string fe = "B";
}

Visual C # скажет мне, что B.fe скрывает A.fe, поэтому я должен использовать новое ключевое слово. Поэтому я изменяю класс B, чтобы он выглядел так:

class B : A {
    public new string fe = "B";
}

И затем у меня есть функция, которая принимает A (но, в силу наследования, также будет принимать B), как это:

class D {
    public static void blah(A anAObject) {
        Console.Writeline(A.fe);
    }
}

Даже когда я передаю ему экземпляр объекта B, который он возьмет без вопросов, он напечатает «A»! Почему это так, и как я могу заставить его работать так, как я хочу, не устанавливая переменную в конструкторе?

Ответы [ 3 ]

6 голосов
/ 19 мая 2010

В этом разница между override и new. new определяет члена, имя которого совпадает с именем в базовом классе. Это не отменяет этого члена. Так что если у вас есть метод, который ожидает экземпляр A, он примет значение A.fe, а не член в производном классе с тем же именем.

Используйте свойство с override вместо:

class A {
    public virtual string fe { get { return "A"; } }
}

class B : A {
    public override string fe { get { return "B"; } }
}
2 голосов
/ 19 мая 2010

Если вы хотите, чтобы ваш член fe был перезаписан производными классами без использования ключевого слова new (именно поэтому вы видите поведение, которое вы видите), просто объявите его virtual в Базовый класс. Тогда ваш код будет выглядеть так:

public class A
{
    public virtual string fe
    {
        get { return "A"; }
    }
}

public class B
{
    public override string fe
    {
        get { return "B"; }
    }
}

Обратите внимание, что для этого необходимо fe a свойство , поскольку поля-члены не могут быть объявлены virtual.

Объяснение того, почему вы не получаете желаемого поведения, заключается в том, что ключевое слово new переопределяет только унаследованный член в том случае, если переменная объявлена ​​как производный класс во время компиляции. Если он объявлен как базовый класс во время компиляции (как anAObject в вашем методе blah), он соответствует версии базового класса (это то, что отличает new от override).

Теперь вы также можете изменить свой метод blah, чтобы преобразовать его входные данные в B, таким образом получая доступ к вашему new fe:

public static void blah(A anAObject) {
    var aBObject = anAObject as B;
    if (aBObject != null)
        Console.WriteLine(aBObject.fe); // would print "B"
    else
        Console.WriteLine(anAObject.fe); // would print "A"
}

Но я бы не рекомендовал это.

1 голос
/ 19 мая 2010
class A {

public virtual string fe { get { return "A"; } set {} }

}

class B {
 public override string fe { get { return "B"; } set {} }
}

это то, что вам нужно ...

AFAIK в D.blah(), объект получает приведение типа A, и поскольку базовое значение не помечено ключевым словом virtual, оно будет вести себя как A, а не как B, даже если тип B ...

...