Разница между новым и переопределением
интересно, в чем разница между следующим:
Случай 1: Базовый Класс
public void DoIt();
Случай 1: унаследованный класс
public new void DoIt();
Случай 2: Базовый Класс
public virtual void DoIt();
случай 2: унаследованный класс
public override void DoIt();
оба случая 1 и 2, похоже, имеют одинаковый эффект на основе тестов, которые я выполнил. Есть ли разница, или предпочтительный способ?
13 ответов:
модификатор override может быть использован на виртуальные методы и должны использоваться на абстрактный метод. Это указывает на компилятор для использования последнего определенного реализация метода. Хотя метод вызывается по ссылке на базовый класс он будет использовать реализация перекрывает его.
public class Base { public virtual void DoIt() { } } public class Derived : Base { public override void DoIt() { } } Base b = new Derived(); b.DoIt(); // Calls Derived.DoItбудем называть
Derived.DoItесли это переопределяетBase.DoIt.новый модификатор указывает компилятор для использования вашего дочернего класса реализация вместо родительского класса реализация. Любой код, который не ссылка на ваш класс, но родитель класс будет использовать родительский класс реализация.
public class Base { public virtual void DoIt() { } } public class Derived : Base { public new void DoIt() { } } Base b = new Derived(); Derived d = new Derived(); b.DoIt(); // Calls Base.DoIt d.DoIt(); // Calls Derived.DoItсначала позвонит
Base.DoIt, потомDerived.DoIt. Это фактически два совершенно разных метода, которые имеют одно и то же имя, а не производный метод, переопределяющий базовый метод.источник: блог Microsoft
виртуальный: указывает, что метод может быть переопределен наследником
переопределить: переопределяет функциональные возможности виртуального метода в базовом классе, обеспечивая различные функциональные возможности.
new:скрывает оригинальный метод (который не должен быть виртуальным), предоставление различных функциональных возможностей. Это должно использоваться только там, где это абсолютно необходимо.
когда вы скрываете метод, вы можете по-прежнему доступ к исходному методу путем приведения к базовому классу. Это полезно в некоторых сценариях, но опасно.
в первом случае вы скрываете определение в родительском классе. Это означает, что он будет вызываться только тогда, когда вы имеете дело с объектом в качестве дочернего класса. Если вы приведете класс к его родительскому типу, будет вызван родительский метод. Во втором случае метод переопределяется и вызывается независимо от того, является ли объект приведенным как дочерний или родительский класс.
попробуйте следующее: (case1)
((BaseClass)(new InheritedClass())).DoIt()Edit: virtual + override разрешаются во время выполнения (поэтому override действительно переопределяет виртуальные методы), в то время как new просто создает новый метод с тем же именем и скрывает старый, он разрешен во время компиляции -> ваш компилятор вызовет метод, который он "видит"
в случае 1 Если вы использовали вызов метода DoIt () унаследованного класса, А тип объявлен как базовый класс, вы увидите действие базового класса даже.
/* Results Class1 Base1 Class2 Class2 */ public abstract class Base1 { public void DoIt() { Console.WriteLine("Base1"); } } public class Class1 : Base1 { public new void DoIt() { Console.WriteLine("Class1"); } } public abstract class Base2 { public virtual void DoIt() { Console.WriteLine("Base2"); } } public class Class2 : Base2 { public override void DoIt() { Console.WriteLine("Class2"); } } static void Main(string[] args) { var c1 = new Class1(); c1.DoIt(); ((Base1)c1).DoIt(); var c2 = new Class2(); c2.DoIt(); ((Base2)c2).DoIt(); Console.Read(); }
разница между этими двумя случаями заключается в том, что в случае 1, база
DoItметод не переопределяется, просто скрыты. Что это означает, что в зависимости от типа переменной зависит от того, какой метод будет вызван. Например:BaseClass instance1 = new SubClass(); instance1.DoIt(); // Calls base class DoIt method SubClass instance2 = new SubClass(); instance2.DoIt(); // Calls sub class DoIt methodЭто может быть очень запутанным и приводит к не ожидаемому поведению и следует избегать, если это возможно. Таким образом, предпочтительным способом будет случай 2.
мой способ иметь в виду оба ключевых слова, что они противоположны друг другу.
override:virtualключевое слово должно быть определено для переопределения метода. Метод с использованиемoverrideключевое слово, которое независимо от типа ссылки(Ссылка на базовый класс или производный класс), если он создается с базовым классом, выполняется метод базового класса. В противном случае выполняется метод производного класса.
new: если ключевое слово используется метод, в отличие отoverrideключевое слово, тип ссылки имеет важное значение. Если он создается с производным классом и ссылочным типом является базовый класс, выполняется метод базового класса. Если он создается с производным классом и ссылочным типом является производный класс, выполняется метод производного класса. А именно, это контрастoverrideключевое слово. Если вы забыли или не добавили новое ключевое слово в метод, компилятор по умолчанию ведет себя как ключевое слово.class A { public string Foo() { return "A"; } public virtual string Test() { return "base test"; } } class B: A { public new string Foo() { return "B"; } } class C: B { public string Foo() { return "C"; } public override string Test() { return "derived test"; } }звонок в главная:
A AClass = new B(); Console.WriteLine(AClass.Foo()); B BClass = new B(); Console.WriteLine(BClass.Foo()); B BClassWithC = new C(); Console.WriteLine(BClassWithC.Foo()); Console.WriteLine(AClass.Test()); Console.WriteLine(BClassWithC.Test());выход:
A B B base test derived test
Если ключевое слово
overrideиспользуется в производном классе, а затем переопределяет родительский метод.Если Ключевое Слово
newиспользуется в производном классе, а затем производный метод, скрытый родительским методом.
статья ниже находится в vb.net но я думаю, что объяснение о новых переопределениях vs очень легко понять.
https://www.codeproject.com/articles/17477/the-dark-shadow-of-overrides
в какой-то момент в статье, есть такая фраза:
В общем случае Shadows принимает функцию, связанную с типом is вызывается, в то время как переопределения предполагает реализацию объекта выполненный.
в принятый ответ на этот вопрос идеален, но я думаю, что эта статья дает хорошие примеры, чтобы добавить лучший смысл о различиях между этими двумя ключевыми словами.
из всех тех, новая - Это самая запутанная. Экспериментируя, новое ключевое слово похоже на предоставление разработчикам возможности переопределить реализацию наследующего класса с реализацией базового класса, явно определив тип. Это как думать наоборот.
в приведенном ниже примере результат будет возвращать " производный результат "до тех пор, пока тип не будет явно определен как тест базового класса, только тогда "базовый результат" будет возвращенный.
class Program { static void Main(string[] args) { var test = new DerivedClass(); var result = test.DoSomething(); } } class BaseClass { public virtual string DoSomething() { return "Base result"; } } class DerivedClass : BaseClass { public new string DoSomething() { return "Derived result"; } }
функциональная разница не будет показана в этих тестах:
BaseClass bc = new BaseClass(); bc.DoIt(); DerivedClass dc = new DerivedClass(); dc.ShowIt();в этом примере Doit, который называется, это тот, который вы ожидаете, что будет вызван.
чтобы увидеть разницу, вы должны сделать это:
BaseClass obj = new DerivedClass(); obj.DoIt();вы увидите, если вы запустите этот тест, что в случае 1 (Как вы определили), то
DoIt()наBaseClassназывается, в случае 2 (Как вы его определили),DoIt()наDerivedClassназывается.
у меня был тот же вопрос и это действительно сбивает с толку, вы должны учитывать, что переопределить и новая ключевые слова, работающие только с объектами типа базовый класс и значение производного класса. В этом случае только вы увидите эффект переопределения и новый: Так что если у вас есть
class AиB,Bнаследует отA, затем вы создаете экземпляр объекта следующим образом:A a = new B();теперь при вызове методов будет принимать его состояние в рассмотрение. переопределить: означает, что он расширяет функцию метода, а затем использует метод в производном классе, тогда как новая попросите компилятор скрыть метод в производном классе и вместо этого использовать метод в базовом классе. Вот очень хороший взгляд на эту тему:
в первом случае он вызовет производный класс DoIt() метод, потому что новое ключевое слово скрывает базовый класс DoIt () метод.
во втором случае он вызовет overriden DoIt ()
public class A { public virtual void DoIt() { Console.WriteLine("A::DoIt()"); } } public class B : A { new public void DoIt() { Console.WriteLine("B::DoIt()"); } } public class C : A { public override void DoIt() { Console.WriteLine("C::DoIt()"); } }давайте создадим экземпляр этих классов
A instanceA = new A(); B instanceB = new B(); C instanceC = new C(); instanceA.DoIt(); //A::DoIt() instanceB.DoIt(); //B::DoIt() instanceC.DoIt(); //B::DoIt()все ожидаемо выше. Давайте установим instanceB и instanceC в instanceA и вызовем метод DoIt () и проверим результат.
instanceA = instanceB; instanceA.DoIt(); //A::DoIt() calls DoIt method in class A instanceA = instanceC; instanceA.DoIt();//C::DoIt() calls DoIt method in class C because it was overriden in class C
Comments