在基本类型“virtual”中声明一个方法,然后在子类型中使用“override”关键字重写它,与在子类型中声明匹配的方法时简单地使用“new”关键字相比,两者之间有什么区别?
当前回答
我的解释来自于使用属性来帮助理解差异。
重写很简单,对吧?底层类型覆盖父类型。
新可能是误导(对我来说是)。使用属性更容易理解:
public class Foo
{
public bool GetSomething => false;
}
public class Bar : Foo
{
public new bool GetSomething => true;
}
public static void Main(string[] args)
{
Foo foo = new Bar();
Console.WriteLine(foo.GetSomething);
Bar bar = new Bar();
Console.WriteLine(bar.GetSomething);
}
使用调试器,你可以注意到Foo Foo有两个GetSomething属性,因为它实际上有两个版本的属性,Foo's和Bar's,为了知道使用哪个,c#“选择”当前类型的属性。
如果你想使用Bar的版本,你应该使用override或使用Foo Foo代替。
Bar Bar只有1,因为它想要GetSomething的全新行为。
其他回答
下面是一些代码来理解虚拟方法和非虚拟方法行为的区别:
class A
{
public void foo()
{
Console.WriteLine("A::foo()");
}
public virtual void bar()
{
Console.WriteLine("A::bar()");
}
}
class B : A
{
public new void foo()
{
Console.WriteLine("B::foo()");
}
public override void bar()
{
Console.WriteLine("B::bar()");
}
}
class Program
{
static int Main(string[] args)
{
B b = new B();
A a = b;
a.foo(); // Prints A::foo
b.foo(); // Prints B::foo
a.bar(); // Prints B::bar
b.bar(); // Prints B::bar
return 0;
}
}
我的解释来自于使用属性来帮助理解差异。
重写很简单,对吧?底层类型覆盖父类型。
新可能是误导(对我来说是)。使用属性更容易理解:
public class Foo
{
public bool GetSomething => false;
}
public class Bar : Foo
{
public new bool GetSomething => true;
}
public static void Main(string[] args)
{
Foo foo = new Bar();
Console.WriteLine(foo.GetSomething);
Bar bar = new Bar();
Console.WriteLine(bar.GetSomething);
}
使用调试器,你可以注意到Foo Foo有两个GetSomething属性,因为它实际上有两个版本的属性,Foo's和Bar's,为了知道使用哪个,c#“选择”当前类型的属性。
如果你想使用Bar的版本,你应该使用override或使用Foo Foo代替。
Bar Bar只有1,因为它想要GetSomething的全新行为。
不标记方法意味着:使用对象的编译类型绑定该方法,而不是运行时类型(静态绑定)。
用虚方法标记方法:使用对象的运行时类型绑定该方法,而不是编译时类型(动态绑定)。
在派生类中使用override标记基类虚方法意味着:这是使用对象的运行时类型绑定的方法(动态绑定)。
在派生类中用new标记基类虚方法意味着:这是一个新方法,它与基类中同名的方法没有关系,它应该使用对象的编译时类型进行绑定(静态绑定)。
在派生类中不标记基类虚方法意味着:该方法被标记为new(静态绑定)。
将一个方法标记为抽象意味着:这个方法是虚的,但是我不会为它声明一个主体,而且它的类也是抽象的(动态绑定)。
“new”关键字不会重写,它表示一个与基类方法无关的新方法。
public class Foo
{
public bool DoSomething() { return false; }
}
public class Bar : Foo
{
public new bool DoSomething() { return true; }
}
public class Test
{
public static void Main ()
{
Foo test = new Bar ();
Console.WriteLine (test.DoSomething ());
}
}
它输出false,如果你使用override,它会输出true。
(基本代码取自Joseph Daigle)
所以,如果你在做真正的多态性,你应该总是OVERRIDE。唯一需要使用“new”的地方是当方法与基类版本没有任何关联时。
using System;
using System.Text;
namespace OverrideAndNew
{
class Program
{
static void Main(string[] args)
{
BaseClass bc = new BaseClass();
DerivedClass dc = new DerivedClass();
BaseClass bcdc = new DerivedClass();
// The following two calls do what you would expect. They call
// the methods that are defined in BaseClass.
bc.Method1();
bc.Method2();
// Output:
// Base - Method1
// Base - Method2
// The following two calls do what you would expect. They call
// the methods that are defined in DerivedClass.
dc.Method1();
dc.Method2();
// Output:
// Derived - Method1
// Derived - Method2
// The following two calls produce different results, depending
// on whether override (Method1) or new (Method2) is used.
bcdc.Method1();
bcdc.Method2();
// Output:
// Derived - Method1
// Base - Method2
}
}
class BaseClass
{
public virtual void Method1()
{
Console.WriteLine("Base - Method1");
}
public virtual void Method2()
{
Console.WriteLine("Base - Method2");
}
}
class DerivedClass : BaseClass
{
public override void Method1()
{
Console.WriteLine("Derived - Method1");
}
public new void Method2()
{
Console.WriteLine("Derived - Method2");
}
}
}
推荐文章
- c#:如何获得一个字符串的第一个字符?
- String类中的什么方法只返回前N个字符?
- 更好的方法将对象转换为int类型
- 我可以将c#字符串值转换为转义字符串文字吗?
- 在c#中转换char到int
- c#中朋友的对等物是什么?
- 关键字使用virtual+override vs. new
- 在ASP中选择Tag Helper。NET Core MVC
- 如何在没有任何错误或警告的情况下找到构建失败的原因
- 跨线程操作无效:控件“textBox1”从创建它的线程以外的线程访问
- 否ConcurrentList<T>在。net 4.0?
- 在c#中解析字符串为日期时间
- 由Jon Skeet撰写的《Singleton》澄清
- 自定义数字格式字符串始终显示符号
- 单元测试无效方法?