Что такое Тень?

В С#, что означает термин "затенение"? Я прочитал эту ссылку, но не понял ее полностью.

Ответ 1

Затенение скрывает метод в базовом классе. Используя пример в связанном вами вопросе:

class A 
{
   public int Foo(){ return 5;}
   public virtual int Bar(){return 5;}
}
class B : A
{
   public new int Foo() { return 1;}
   public override int Bar() {return 1;}
}

Класс B переопределяет виртуальный метод Bar. Он скрывает (тени) не виртуальный метод Foo. Override использует ключевое слово переопределить. Затенение выполняется с помощью нового ключевого слова.

В приведенном выше коде, если вы не использовали ключевое слово new при определении метода Foo в классе B, вы получите предупреждение этого компилятора:

'test.B.Foo()' hides inherited member 'test.A.Foo()'. Use the new keyword if hiding was intended.

Ответ 2

  • Переопределение: переопределение существующего метода в базовом классе
  • Тень: создание совершенно нового метода с той же сигнатурой, что и в базовом классе

Ответ 3

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

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

У меня также есть производный класс, который также определяет метод M:

public class B : A
{
    // could be either "new" or "override", "new" is default
    public void M() { Console.WriteLine("In B.M()."); }
}

Теперь предположим, что я пишу такую ​​программу:

A alpha = new B(); // it really a B but I cast it to an A
alpha.M();

У меня есть два разных варианта того, как я хочу, чтобы это было реализовано. Поведение по умолчанию - это вызов версии M. (Это идентично поведению, если вы применили ключевое слово < new к B.M().)

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

В качестве альтернативы мы могли бы указать "override" на B.M(). В этом случае alpha.M() назвал бы B-версию M.

Ответ 4

Затенение заключается в скрытии метода базового класса с новым определением в дочернем классе.

Разница между скрытием и переопределением связана с тем, как вызывается метод.

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

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

При вызове соответствующего метода:

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

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

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

В целом затенение - плохая идея, так как она вводит разницу в поведении экземпляра в зависимости от ссылки, которую мы имеем к ней.

Ответ 5

Расширение на Кент правильный ответ

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

  • Тени: метод, вызываемый, зависит от типа ссылки в точке, в которой сделан вызов.
  • Переопределение: вызываемый метод зависит от типа объекта в точке, в которой выполняется вызов.

Ответ 6

Здесь статья MSDN относительно Shadowing. Примеры языка находятся в Visual Basic (к сожалению, на MSDN не существует эквивалентной страницы С#), но в целом это касается понятий и, надеюсь, должно помочь вам понять в любом случае.

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

Ответ 7

Если вы хотите скрыть метод базового класса, используйте переопределение в базе [виртуальный метод в базе]

если вы хотите скрыть метод класса Child, использовать новый в базе [невиртуальный метод в базе] → тень

Base B=new Child()

B.VirtualMethod() → Вызывает метод класса Child

B.NonVirtualMethod() → Вызов Метод базового класса

Ответ 8

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

Ответ 9

 private static int x = 10;


static void Main(string[] args)
    { int x = 20;
        if (Program.x == 10)
        {
            Console.WriteLine(Program.x);
        }
        Console.WriteLine(x);}

Вывод:

10 20