Почему я не могу использовать виртуальные /переопределить переменные класса, как я могу на методах?

В следующем примере я могу создать виртуальный метод Show() в унаследованном , а затем переопределите его в наследующем классе.

Я хочу сделать то же самое с защищенной переменной класса prefix но я получаю ошибку:

  

Модификатор 'virtual' недопустим   для этого предмета

Но так как я не могу определить эту переменную как virtual /override в моих классах, я получаю предупреждение :

  

TestOverride234355.SecondaryTransaction.prefix»   скрывает унаследованный член   'TestOverride234355.Transaction.prefix.   Используйте новое ключевое слово, если скрытие было   предназначен.

К счастью, когда я добавляю ключевое слово new, все работает нормально , что нормально, так как я получаю то же самое функциональность, но это поднимает два вопроса :

  1. Почему я могу использовать virtual /override для методов, но не для переменных защищенного класса?

  2. Какая разница на самом деле между подходом виртуального /переопределения и подходом "скрыть это с новым", поскольку, по крайней мере, в этом примере они предлагают одинаковую функциональность?

код:

using System;

namespace TestOverride234355
{
    public class Program
    {
        static void Main(string[] args)
        {
            Transaction st1 = new Transaction { Name = "name1", State = "state1" };
            SecondaryTransaction st2 = 
                new SecondaryTransaction { Name = "name1", State = "state1" };

            Console.WriteLine(st1.Show());
            Console.WriteLine(st2.Show());

            Console.ReadLine();
        }
    }

    public class Transaction
    {
        public string Name { get; set; }
        public string State { get; set; }

        protected string prefix = "Primary";

        public virtual string Show()
        {
            return String.Format("{0}: {1}, {2}", prefix, Name, State);
        }
    }

    public class SecondaryTransaction : Transaction
    {
        protected new string prefix = "Secondary";

        public override string Show()
        {
            return String.Format("{0}: {1}, {2}", prefix, Name, State);
        }
    }
}
12 голосов | спросил Edward Tanguay 4 MarpmThu, 04 Mar 2010 13:16:26 +03002010-03-04T13:16:26+03:0001 2010, 13:16:26

5 ответов


0

Скорее создайте свойство для префиксного члена - таким образом, вы можете установить свойство виртуальным /абстрактным

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

Вы также не можете поместить переменные экземпляра в интерфейс

ответил saret 4 MarpmThu, 04 Mar 2010 13:21:35 +03002010-03-04T13:21:35+03:0001 2010, 13:21:35
0

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

Не существует такого механизма для полей, так как они предназначены для быстрого доступа.

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

Если вы обращаетесь к виртуальному члену через указатель на базовый класс, вы никогда не получите доступ к члену, определенному как «новый» в производном классе, что является отличием, упомянутым во второй части вашего вопроса.

ответил Timores 4 MarpmThu, 04 Mar 2010 13:32:29 +03002010-03-04T13:32:29+03:0001 2010, 13:32:29
0

В вашем примере, если вы не переопределили «Show» в классе SecondaryTransaction, то вызов Show для экземпляра SecondaryTransaction фактически вызовет метод в базовом классе (Transaction), который, следовательно, будет использовать «Show» в базовом классе, что приводит к выводу:

Primary: name1, state1 
Primary: name1, state1

Таким образом, в зависимости от того, какой метод вы вызываете (т. е. один для базового класса или дочернего класса), код будет иметь другое значение для «префикса», что будет кошмаром для сопровождения. Я подозреваю, что вы, вероятно, хотите /должны сделать, это выставить свойство в транзакции, которое переносит «префикс».

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

Что бы я делал (если бы я абсолютно не хотел /не мог использовать свойства):

public class Transaction
{
    public string Name { get; set; }
    public string State { get; set; }
    protected string prefix = "Primary";
    public virtual string Show()
    {
        return String.Format("{0}: {1}, {2}", prefix, Name, State);
    }
}
public class SecondaryTransaction : Transaction
{ 
    public SecondaryTransaction()
    {
        prefix = "Secondary";
    }
    public override string Show()
    {
        return String.Format("{0}: {1}, {2}", prefix, Name, State);
    }
}

Изменить: (согласно моему комментарию к другому ответу)

Если вы вызываете ctor вашего базового класса и вам нужно установить значение, вам, вероятно, придется изменить Transaction, возможно, так:

public class Transaction
{
    public string Name { get; set; }
    public string State { get; set; }
    protected string prefix = "Primary";
    // Declared as virtual ratther than abstract to avoid having to implement "TransactionBase"
    protected virtual void Initialise()
    { }
    public Transaction()
    {
        Initialise();
    }
    public virtual string Show()
    {
        return String.Format("{0}: {1}, {2}", prefix, Name, State);
    }
}
public class SecondaryTransaction : Transaction
{ 
    protected override void Initialise()
    {
        prefix = "Secondary";
    }
    public override string Show()
    {
        return String.Format("{0}: {1}, {2}", prefix, Name, State);
    }
}
ответил Rob 4 MarpmThu, 04 Mar 2010 13:28:00 +03002010-03-04T13:28:00+03:0001 2010, 13:28:00
0

Почему вы хотите переопределить защищенную переменную, конечно же, все, что вам нужно сделать, - это установить ее в другое значение в переопределяющем классе (возможно, в конструкторе)?

ответил Paddy 4 MarpmThu, 04 Mar 2010 13:18:18 +03002010-03-04T13:18:18+03:0001 2010, 13:18:18
0

Вы не можете, потому что это бесполезно. Что бы вы сделали, переопределив поле?

ответил Bart van Heukelom 4 MarpmThu, 04 Mar 2010 13:19:13 +03002010-03-04T13:19:13+03:0001 2010, 13:19:13

Похожие вопросы

Популярные теги

security × 330linux × 316macos × 2827 × 268performance × 244command-line × 241sql-server × 235joomla-3.x × 222java × 189c++ × 186windows × 180cisco × 168bash × 158c# × 142gmail × 139arduino-uno × 139javascript × 134ssh × 133seo × 132mysql × 132