Какой эффект имеет ключевое слово «new» в C # и почему оно только предупреждение, когда не используется? - PullRequest
7 голосов
/ 10 августа 2009

Рассмотрим следующий код:

public abstract class Test1
{
    public object Data { get; set; }
}

public abstract class Test2<T> : Test1
{
    public T Data { get; set; }
}

Это выдаст следующее предупреждение:

«Test2.Data» скрывает унаследованный элемент «Test1.Data». Используйте новое ключевое слово, если было скрыто.

Почему это только предупреждение и какой эффект будет иметь добавление ключевого слова "new"?

Согласно моему тестированию, я не могу найти никакой разницы после добавления "нового" ключевого слова.

Не поймите меня неправильно, я весь за откровенность, но мне было любопытно, что было бы полезно добавить "new".

Я думаю только о том, что это может быть:

  • Улучшенная читаемость
  • Некоторая экономия во время выполнения, когда компилятору не осталось, чтобы вычислить неизбежное на долгом пути

Ответы [ 4 ]

21 голосов
/ 10 августа 2009

Единственный эффект, который дает ключевое слово new, - удаление предупреждения. Целью получения предупреждения, когда ключевое слово new не используется, является предотвращение случайного дублирования метода, когда вы действительно хотели его переопределить.

3 голосов
/ 10 августа 2009

new используется для скрытия метода или свойства базового класса. Это не , как переопределение: член не должен иметь такую ​​же подпись, как скрытый член базового класса, и не участвует в полиморфизме.

Пример:

class A
{
    public virtual void Test()
    {
        Console.WriteLine("A.Test");
    }
}

class B : A
{
    public new void Test()
    {
        Console.WriteLine("B.Test");
    }
}

class B : A
{
    public override void Test()
    {
        Console.WriteLine("C.Test");
    }
}

public static void Main(string[] args)
{
    A aa = new A();
    aa.Test(); // Prints "A.Test"

    A ab = new B();
    ab.Test(); // Prints "A.Test" because B.Test doesn't overrides A.Test, it hides it

    A ac = new C();
    ac.Test(); // Prints "C.Test" because C.Test overrides A.Test

    B b = new B();
    b.Test(); // Prints "B.Test", because the actual type of b is known at compile to be B
}
2 голосов
/ 10 августа 2009

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

1 голос
/ 24 июня 2015

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

Не существует общего средства, с помощью которого C # может определить, когда в классы были добавлены различные методы, и, следовательно, у компилятора нет возможности узнать, знал ли автор метода производного класса о существовании одноименного имени метод базового класса , если автор метода производного класса прямо указывает компилятору, знает ли он о существовании метода базового класса, используя модификаторы new или override.

Я бы предложил интерпретировать модификаторы (или их отсутствие) как:

  • Нет - автору неизвестно о существовании метода базового класса, и поэтому не может ожидать выполнения своего контракта.

  • new - автору известен метод базового класса, и по какой-либо причине он написал этот метод, чтобы не выполнять его.

  • override - автору известен метод базового класса и его контракт, и он написал этот метод для его выполнения.

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

...