关于c#:new和override之间的区别

Difference between new and override

想知道以下两者之间的区别是什么:

案例1:基本类

1
public void DoIt();

案例1:继承类

1
public new void DoIt();

案例2:基本类

1
public virtual void DoIt();

案例2:继承类

1
public override void DoIt();

根据我运行的测试,案例1和2似乎都有相同的效果。有什么不同,还是一种首选的方式?


The override modifier may be used on
virtual methods and must be used on
abstract methods. This indicates for
the compiler to use the last defined
implementation of a method. Even if
the method is called on a reference to
the base class it will use the
implementation overriding it.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
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.DoItoverrides Base.DoIt

The new modifier instructs the
compiler to use your child class implementation
instead of the parent class
implementation. Any code that is not
referencing your class but the parent
class will use the parent class
implementation.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
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。它们是两个独立的有效方法,它说有两个相同的名字,而不是"overriding衍生方法的基本方法。

来源:微软博客


虚拟indicates方法:这可能是一个inheritor市。

overrides重写:《功能性的虚拟方法在一个基础类,提供不同的功能性。

新:《hides原方法(这不可能是虚拟的),提供不同的功能性。这应该只被用来在它是绝对必要的。

当你隐藏的方法,你可以通过访问IP的原始方法铸造的基础类。这是有用的在一些场景,但危险。


在第一例你是藏在父母的定义的类。这意味,这将是invoked只读的时候你是处理与"儿童为对象的类。如果你现在其类型的父母,父母的方法将invoked。在第二次审,overridden和冰的方法,将invoked大学的对象是否regardless冰铸AA级儿童或家长。


尝试以下:(case1)

1
((BaseClass)(new InheritedClass())).DoIt()

编辑:虚拟+分辨是运行时重写(override overrides婊子真的虚拟方法),只是在新创建的新方法,用相同的名称和hides旧的,它是如何分辨的编译时编译器会>你呼叫的方法,它看起来从宫殿的窗户,看到的


我的方法记住两个关键词,它们彼此是相反的。

override:必须定义virtual关键字来重写该方法。使用override关键字的方法,无论引用类型(引用基类或派生类)如何,如果用基类实例化,则运行基类方法。否则,将运行派生类的方法。

new:如果某个方法使用了关键字,与override关键字不同,引用类型很重要。如果它是用派生类实例化的,并且引用类型是基类,则运行基类的方法。如果它是用派生类实例化的,并且引用类型是派生类,则将运行派生类的方法。也就是说,它是override关键字的对比。顺便说一下,如果您忘记或忽略了向方法中添加新关键字,编译器的行为默认为使用new关键字。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
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";
    }
}

主叫:

1
2
3
4
5
6
7
8
9
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());

输出:

1
2
3
4
5
A
B
B
base test
derived test

作为一个说明,我还没有接触C++ 3年,但我相信我解释的方式仍然对你有帮助。


在案例1,如果你用电话的做法()的类继承的类冰宣布当这类AA的基地,你会看到动作类的基础上达到平衡。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
/* 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不overridden get方法,正是隐藏的。什么这意味的是,这取决于类型的变量,这将取决于对所谓的get方法。例如:

1
2
3
4
5
BaseClass instance1 = new SubClass();
instance1.DoIt(); // Calls base class DoIt method

SubClass instance2 = new SubClass();
instance2.DoIt(); // Calls sub class DoIt method

这可能是真的confusing和结果在非预期行为和应该避免,如果可能的。这样的方式将是首选的案例2。


在所有这些中,新的是最令人困惑的。通过试验,新的关键字就像给开发人员一个选项,通过显式定义类型,用基类实现覆盖继承类实现。这就像反过来想。

在下面的示例中,结果将返回"派生结果",直到类型被显式定义为基类测试,然后才返回"基本结果"。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
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";
    }
}


下面的文章在vb.net中,但是我认为关于新的vs重写的解释很容易理解。

https://www.codeproject.com/articles/17477/the-dark-shadow-of-overrides

在本文的某一点上,有一句话:

In general, Shadows assumes the function associated with the type is
invoked, while Overrides assumes the object implementation is
executed.

对这个问题的公认答案是完美的,但我认为本文提供了很好的例子来增加这两个关键词之间的差异的更好含义。


如果override冰关键字用于derive类是其父母的替代方法。

如果new冰关键字用于derive类方法则derive hided城市父母的方法。


在第一种情况下,它将调用派生类doit()方法,因为new关键字隐藏了基类doit()方法。

在第二种情况下,它将调用overriden doit()。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
  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()");
    }
}

让我们创建这些类的实例

1
2
3
4
5
6
7
8
   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()方法检查结果。

1
2
3
4
5
    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


在仇恨一样的问题和它的真的confusing, 你应该考虑新的关键词,重写和工作对象的只读型基部与类和衍生类的价值。在这个病例只有你会看到《纽约大学和替代效应: 所以,如果你有class ABBinherits从A,那么你实例化的对象是这样的:

1
A a = new B();

现在的在线呼叫方法将把其纳入国家编码。 重写:均值,这extends的功能的方法,那么它的辨别方法衍生类的尽头,告诉编译器的两个新的方法隐藏在衍生类的方法和使用的类,而不是基地。 这是一个很好的视线,这两个主题:

msdn.microsoft.com http:/ / /美国/图书馆/ ms173153 28V vs.140 %=%,D = hv.2 29.aspx吗?F = 255 &;mspperror = 2147217396


《泛函差分将不会是显示在这些测试:

1
2
3
4
5
6
7
BaseClass bc = new BaseClass();

bc.DoIt();

DerivedClass dc = new DerivedClass();

dc.ShowIt();

在本例中,这是所谓的"做你希望是一个被称为。

在二阶差分,你有看到这样做:

1
2
3
BaseClass obj = new DerivedClass();

obj.DoIt();

你会看到,如果你运行你的测试案例1(当你定义它),在《DoIt()BaseClass冰称,在案例2(当你定义它),《DoIt()DerivedClass所谓的冰。