Новое ключевое слово в сигнатуре метода

Во время выполнения рефакторинга я создал метод, подобный приведенному ниже примеру. Тип данных был изменен для простоты.

У меня раньше была инструкция присваивания:

MyObject myVar = new MyObject();

Он был реорганизован на это случайно:

private static new MyObject CreateSomething()
{
  return new MyObject{"Something New"};
}

Это было результатом ошибки вырезания/вставки с моей стороны, но ключевое слово new в private static new является допустимым и компилируется.

Вопрос. Что означает ключевое слово new в сигнатуре метода? Я предполагаю, что это что-то введенное в С# 3.0?

Как это отличается от override?

Ответ 1

Новая ссылка на ключевое слово из MSDN:

Ссылка MSDN

Вот пример, который я нашел в сети от Microsoft MVP, который имел смысл: Ссылка на оригинал

public class A
{
   public virtual void One();
   public void Two();
}

public class B : A
{
   public override void One();
   public new void Two();
}

B b = new B();
A a = b as A;

a.One(); // Calls implementation in B
a.Two(); // Calls implementation in A
b.One(); // Calls implementation in B
b.Two(); // Calls implementation in B

Переопределение можно использовать только в особых случаях. Из MSDN:

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

Поэтому ключевое слово "новое" необходимо, чтобы вы могли "переопределять" не виртуальные и статические методы.

Ответ 2

Нет, это на самом деле не "новое" (простите за каламбур). Он в основном используется для "скрытия" метода. IE:

public class Base
{
   public virtual void Method(){}
}

public class Derived : Base
{
   public new void Method(){}
}

Если вы сделаете это:

Base b = new Derived();
b.Method();

Метод в базе - это тот, который будет вызываться, а не тот, который был выведен.

Дополнительная информация: http://www.akadia.com/services/dotnet_polymorphism.html

Повторите свое редактирование: В примере, который я дал, если вы должны "переопределить" вместо использования "нового", тогда, когда вы вызываете b.Method(); метод Derived класса будет вызван из-за полиморфизма.

Ответ 3

Как объяснили другие, он используется, чтобы скрыть существующий метод. Это полезно для переопределения метода, который не является виртуальным в родительском классе.

Имейте в виду, что создание "нового" элемента не является полиморфным. Если вы примените объект к базовому типу, он не будет использовать член производного типа.

Если у вас есть базовый класс:

public class BaseClass
{
    public void DoSomething() { }
}

И тогда производный класс:

public class DerivedType : BaseClass
{
    public new void DoSomething() {}

}

Если вы объявляете тип DerivedType, а затем выполняете его, метод DoSomething() не является полиморфным, он будет вызывать метод базового класса, а не производный.

BaseClass t = new DerivedType();
t.DoSomething();// Calls the "DoSomething()" method of the base class.

Ответ 4

Из документов:

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

Что это означает на практике:

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

Лично я стараюсь избегать "нового" ключевого слова, так как это обычно означает, что у меня неправильная иерархия классов, но есть моменты, когда это может быть полезно. Одно место - для управления версиями и обратной совместимости.

В MSDN для этого.

Ответ 5

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

Ответ 6

Короче говоря - он НЕ требуется, он изменяет поведение НЕТ, и это ПОЛНОСТЬЮ для читаемости.

Вот почему в VS вы увидите немного squiggly, но ваш код будет компилироваться и работать отлично и, как ожидалось.

Нужно ли задаваться вопросом, действительно ли стоит создавать ключевое слово new, когда все это означает, что разработчик признает "Да, я знаю, что скрываю базовый метод, да, я знаю, что я не делаю ничего, связанного с virtual или overriden (полиморфизм) - я действительно хочу просто создать его собственный метод".

Это немного странно для меня, но, может быть, только потому, что я исхожу из фона Java и существует это фундаментальное различие между C# inheritance и Java: In Java, методы являются виртуальными по умолчанию, если не указано final. В C# методы являются окончательными/конкретными по умолчанию, если не указано virtual.

Ответ 7

От MSDN:

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

Ответ 8

Будьте осторожны в этом. У вас есть метод, определенный в интерфейсе, который реализован в базовом классе. Затем вы создаете производный класс, который скрывает метод интерфейса, но специально не объявляет производный класс как реализацию интерфейса. Если вы затем вызовете метод с помощью ссылки на интерфейс, будет вызван метод базового класса. Однако, если ваш производный класс специально реализует интерфейс, тогда его метод будет называться в зависимости от того, какой тип ссылки используется.

interface IMethodToHide
{
    string MethodToHide();
}

class BaseWithMethodToHide : IMethodToHide
{
    public string MethodToHide()
    {
        return "BaseWithMethodToHide";
    }
}

class DerivedNotImplementingInterface   : BaseWithMethodToHide
{
    new public string MethodToHide()
    {
        return "DerivedNotImplementingInterface";
    }
}

class DerivedImplementingInterface : BaseWithMethodToHide, IMethodToHide
{
    new public string MethodToHide()
    {
        return "DerivedImplementingInterface";
    }
}

class Program
{
    static void Main()
    {
        var oNoI = new DerivedNotImplementingInterface();
        IMethodToHide ioNoI = new DerivedNotImplementingInterface();

        Console.WriteLine("reference to the object type DerivedNotImplementingInterface calls the method in the class " 
            + oNoI.MethodToHide());
        // calls DerivedNotImplementingInterface.MethodToHide()
        Console.WriteLine("reference to a DerivedNotImplementingInterface object via the interfce IMethodToHide calls the method in the class " 
            + ioNoI.MethodToHide());
        // calls BaseWithMethodToHide.MethodToHide()
        Console.ReadLine();

        var oI = new DerivedImplementingInterface();
        IMethodToHide ioI = new DerivedImplementingInterface();

        Console.WriteLine("reference to the object type DerivedImplementingInterface calls the method in the class " 
            + oI.MethodToHide());
        // calls DerivedImplementingInterface.MethodToHide()
        Console.WriteLine("reference to a DerivedImplementingInterface object via the interfce IMethodToHide calls the method in the class " 
            + ioI.MethodToHide());
        // calls DerivedImplementingInterface.MethodToHide()
        Console.ReadLine();

    }
}