Новый оператор в C# не переопределяет участника базового класса

Я смущен относительно почему new оператор не работает, поскольку я ожидал это к.

Примечание: Все классы ниже определяются в том же пространстве имен, и в том же файле.

Этот класс позволяет Вам снабжать префиксом любое содержание, записанное в консоль с некоторыми предоставленными тексту.

public class ConsoleWriter
{
    private string prefix;

    public ConsoleWriter(string prefix)
    {
        this.prefix = prefix;
    }

    public void Write(string text)
    {
        Console.WriteLine(String.Concat(prefix,text));
    }
}

Вот базовый класс:

public class BaseClass
{
    protected static ConsoleWriter consoleWriter = new ConsoleWriter("");

    public static void Write(string text)
    {
        consoleWriter.Write(text);
    }
}

Вот реализованный класс:

public class NewClass : BaseClass
{
    protected new static ConsoleWriter consoleWriter = new ConsoleWriter("> ");
}

Теперь вот код для выполнения этого:

class Program
{
    static void Main(string[] args)
    {
        BaseClass.Write("Hello World!");
        NewClass.Write("Hello World!");

        Console.Read();
    }
}

Таким образом, я ожидал бы, что вывод будет

Hello World!
> Hello World!

Но вывод

Hello World!
Hello World!

Я не понимаю, почему это происходит. Вот мой мыслительный процесс относительно того, что происходит:

  1. CLR звонит BaseClass.Write() метод
  2. CLR инициализирует BaseClass.consoleWriter участник.
  3. Метод называют и выполняют с BaseClass.consoleWriter переменная

Затем

  1. CLR звонит NewClass.Write()
  2. CLR инициализирует NewClass.consoleWriter объект.
  3. CLR видит, что реализация находится в BaseClass, но метод наследован через
  4. CLR выполняет метод локально (в NewClass) использование NewClass.consoleWriter переменная

Я думал, что это - то, как структура наследования работает?

Кто-то может помочь мне понять, почему это не работает?

--

Обновление:

Этот сценарий работал бы следующим образом (как я реализовал его),

public class LogBase
{
   protected static TraceSource logger = new TraceSource("");

   public static void Error (string text) { logger.WriteError(text); }
   public static void Info (string text) { logger.WriteInformation(text); }
   public static void Warning (string text) { logger.WriteWarning(text); }
   public static void Verbose (string text) { logger.WriteVerbose(text); }
}

// DataAccess logging
public class DALog : LogBase
{
    protected new static TraceSource logger = new TraceSource("DataAccess");
}

// BusinessObjects logging
public class BOLog : LogBase
{
    protected new static TraceSource logger = new TraceSource("Objects");
}

// BusinessLogic logging
public class BLLog : LogBase
{
    protected new static TraceSource logger = new TraceSource("Logic");
}

// WebUI logging
public class WebUILog : LogBase
{
    protected new static TraceSource logger = new TraceSource("WebUI");
}

Так как причина, я не должен копировать код для каждого класса.

--

Обновление (после выбранного решения):

Таким образом, для обхождения этой проблемы, вместо того, чтобы использовать базовые классы, я определил функциональность один. Затем созданные новые классы, которые содержали экземпляры Singleton для каждого слоя:

public sealed class LogBase
{
   private TraceSource logger = null;

   public static LogBase GetLogger(string loggerName) 
   {
       return new LogBase(loggerName);
   }

   private LogBase(string loggerName) { logger = new TraceSource(loggerName); }

   public void Error (string text) { logger.WriteError(text); }
   public void Info (string text) { logger.WriteInformation(text); }
   public void Warning (string text) { logger.WriteWarning(text); }
   public void Verbose (string text) { logger.WriteVerbose(text); }
}

// DataAccess logging - no base class
public class DALog 
{
    private static LogBase logger;

    public static LogBase Instance
    { 
         get 
         { 
              if (logger==null) { logger = new TraceSource("DataAccess"); }
              return logger;
         }
    }
}

...
6
задан Dominic Zukiewicz 18 June 2010 в 14:17
поделиться

4 ответа

Оператор new на самом деле не переопределяет в смысле полиморфизма. Он просто добавляет другой метод, который "случайно" имеет ту же сигнатуру, но рассматривается как отдельный метод. Только если вы явно выполните этот метод в подклассе, будет использована "новая" реализация.

В вашем случае вы реализовали Write только в базовом классе. В нем есть строка, вызывающая consoleWriter. Эта строка ссылается на базовый класс и, таким образом, использует оригинальную реализацию. Она даже не знает о дополнительной реализации в подклассе.

Пересмотрите свой код и рассмотрите его так:

public class BaseClass
{
    protected static ConsoleWriter consoleWriter = new ConsoleWriter("");

    public static void Write(string text)
    {
        consoleWriter.Write(text);
    }
}


public class NewClass : BaseClass
{
    protected static ConsoleWriter anotherConsoleWriter = new ConsoleWriter(">");
}

Ваш BaseClass.Write никогда бы не подумал вызвать другойConsoleWriter вместо consoleWriter.

Если вы хотите, чтобы ваш пример работал, вам нужно либо добавить новую реализацию для Write:

public class NewClass : BaseClass
{
    protected new static ConsoleWriter consoleWriter = new ConsoleWriter(">");

    public static new void Write(string text)
    {
        consoleWriter.Write(text);
    }
}

... либо, что вы, скорее всего, изначально хотели, ввести настоящее переопределение в смысле полиморфизма, используя override вместо new. Однако ваш базовый класс должен поддерживать это, объявляя consoleWriter как virtual. Далее (как вы упомянули в своем комментарии) это работает только в том случае, если вы не делаете эти методы статическими.

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

9
ответ дан 8 December 2019 в 14:40
поделиться

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

Вам нужно, чтобы эти классы были статическими? В противном случае вы можете сделать метод Write виртуальным и переопределить его в производном классе; base.Write (">" + текст);

3
ответ дан 8 December 2019 в 14:40
поделиться

На исходный вопрос ответили другие: поведение, ожидаемое OP, является что вы получаете от переопределения метода, а не от использования new .

В ответах OP он обеспокоен тем, что вы не можете переопределить статические методы. Это правда, но вот блог от msdn, в котором объясняется, почему, и обсуждаются способы борьбы с этим: http://blogs.msdn.com/b/kirillosenkov/archive/2008/02/06/how-to-override-static-methods.aspx

3
ответ дан 8 December 2019 в 14:40
поделиться

Вы знаете, что наследование и переопределение работают для (виртуальных) методов экземпляра, а не статических, верно?

Ваше переопределение защищено и поэтому не отображается за пределами вашего NewClass и потомки. Следовательно, поведение по спец. new позволяет вам создать только новую функцию, на которую можно ссылаться по тому же идентификатору в своем контексте: ваш метод NewClass.Write действительно не имеет ничего общего с вашим BaseClass .Напишите .

1
ответ дан 8 December 2019 в 14:40
поделиться
Другие вопросы по тегам:

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