новое ключевое слово в сигнатуре метода - PullRequest
109 голосов
/ 18 июня 2009

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

У меня ранее был оператор присваивания, подобный этому:

MyObject myVar = new MyObject();

Это был случайный рефакторинг:

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

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

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

Чем это отличается от override?

Ответы [ 8 ]

95 голосов
/ 18 июня 2009

Новая ссылка на ключевое слово из 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:

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

Таким образом, ключевое слово «new» необходимо, чтобы вы могли «переопределять» не виртуальные и статические методы.

58 голосов
/ 18 июня 2009

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

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

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

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

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

Будет вызываться метод в Base, а не метод в производном.

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

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

22 голосов
/ 18 июня 2009

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

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

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

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.
7 голосов
/ 18 июня 2009

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

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

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

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

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

В MSDN содержится много информации для этого .

3 голосов
/ 23 июня 2015

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

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

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

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

3 голосов
/ 18 июня 2009

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

1 голос
/ 18 июня 2009

С MSDN :

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

0 голосов
/ 31 мая 2016

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

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();

    }
}
...