Использование "нового" модификатора в С#

Я прочитал, что модификатор new скрывает метод базового класса.

using System;

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

class B : A
{
    public new void Y()
    {
        // This method HIDES A.Y.
        // It is only called through the B type reference.
        Console.WriteLine("B.Y");
    }
}

class Program
{
    static void Main()
    {
        A ref1 = new A(); // Different new
        A ref2 = new B(); // Polymorpishm
        B ref3 = new B();

        ref1.Y();
        ref2.Y(); //Produces A.Y line #xx
        ref3.Y();
    }
}

Почему ref2.Y(); выводит A.Y в качестве вывода?

Это простой полиморфизм, объект базового класса, указывающий на производный класс, поэтому он должен вызывать производную функцию класса. Я на самом деле Java cum С# coder; эти концепции просто ошеломили мой разум.

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

ref

Ответ 1

В С# методы по умолчанию не являются виртуальными (в отличие от Java). Поэтому вызов метода ref2.Y() не является полиморфным.

Чтобы воспользоваться полиморфизмом, вы должны пометить A.Y() метод как virtual и B.Y() как override.

Что делает new модификатор, просто скрывает член, унаследованный от базового класса. Что действительно происходит в вашем методе Main():

A ref1 = new A();
A ref2 = new B();
B ref3 = new B();

ref1.Y(); // A.Y
ref2.Y(); // A.Y - hidden method called, no polymorphism
ref3.Y(); // B.Y - new method called

Ответ 2

(Только для дополнения других ответов и комментариев от себя.)

Когда используется new, класс (или структура или интерфейс) будет иметь два одинаково выглядящих элемента, один из которых унаследован от базового типа и один объявлен самим типом. Избегайте этого!

Важно: только потому, что вы говорите new, вы не будете удалять старый элемент. Он все еще существует и может быть легко вызван. Член new не заменяет унаследованный. Это неродственный член, который имеет одно и то же имя.

Нехорошо иметь два или более членов в типе, который выглядит одинаково. Это приводит к путанице. Рассмотрим код:

interface IOne
{
  void Y();
}
interface ITwo
{
  void Y();
}
interface IBoth : IOne, ITwo
{
}
class Test
{
  static void M(IBoth obj)
  {
    obj.Y();  // must not compile!
  }
}

Тип IBoth имеет два члена (оба наследуемых), которые выглядят одинаково. В зависимости от конкретного класса obj эти методы могут иметь разные реализации. Вызов obj.Y() неоднозначен. Вам нужно будет указать obj на один из базовых интерфейсов, чтобы решить эту проблему.

Затем рассмотрим этот код:

interface IBase
{
  void Y();
}
interface IDerived : IBase
{
  /* new */ void Y();
}
class Test
{
  static void M(IDerived obj)
  {
    obj.Y();  // allowed; IDerived has two Y, but one hides the other
  }
}

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

Эта ситуация может возникнуть, если базовый тип (здесь IBase) написан другим поставщиком/поставщиком. Пример. Возможно, вы представили Y() в своем интерфейсе в то время, когда база не имела этой функции. Но затем поставщик IBase выпускает новую версию своего продукта, где IBase имеет Y(). Теперь, если вы скомпилируете свой код против своей новой версии, "ваш" Y() все равно будет вызываться, а не их. Но это даст это предупреждение. Предупреждение исчезает, если вы включили new. Но лучше либо (1) полностью удалить ваш метод Y(), если вы определите, что поставщик Y() выполняет задание, или (2) переименует метод Y() к некоему неиспользуемому имени.

Если вам нужен полиморфизм, используйте abstract/virtual (только члены класса) в сочетании с override (в классе наследования). override не будет вводить новых членов, а только новую реализацию существующего (унаследованного) члена. Это можно сделать только для нестатических членов (обычно методов или свойств).

Ответ 3

Тип объекта - A, но ref2 не имеет доступа к версии Y(), которая определена в классе B, потому что этот метод объявлен с новым модификатором, а не модификатором переопределения. В результате объект ref2 отображает то же описание, что и объект A.