在基本类型“ virtual
”中声明一个方法,然后在子类型中使用“ override
”关键字覆盖该方法,而不是在子类型中new
声明匹配方法时简单地使用“ ”关键字,这有什么区别?
在基本类型“ virtual
”中声明一个方法,然后在子类型中使用“ override
”关键字覆盖该方法,而不是在子类型中new
声明匹配方法时简单地使用“ ”关键字,这有什么区别?
Answers:
“ 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 ());
}
}
如果您使用覆盖,它将显示为true。
(摘自Joseph Daigle的基本代码)
因此,如果您正在执行真正的多态性,则应始终覆盖。您需要使用“ new”的唯一地方是该方法与基类版本没有任何关系。
virtual
在基地和override
派生?为什么存在?即使没有代码,代码也仍然可以运行new
-因此,纯粹是可读性吗?
我总是发现通过图片更容易理解这样的事情:
同样,以约瑟夫·戴格尔的代码,
public class Foo
{
public /*virtual*/ bool DoSomething() { return false; }
}
public class Bar : Foo
{
public /*override or new*/ bool DoSomething() { return true; }
}
如果您随后这样调用代码:
Foo a = new Bar();
a.DoSomething();
注意:重要的是我们的对象实际上是一个Bar
,但是我们将其存储在类型变量中Foo
(这与强制转换类似)。
然后,结果将如下所示,具体取决于您使用virtual
/ override
还是new
声明类时。
以下是一些代码,用于了解虚拟方法和非虚拟方法的行为差异:
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;
}
}
new
当根本不使用覆盖时,为什么使用“隐藏”基本方法呢?
virtual
如果编译器在没有virtual
签名的类“
该new
关键字实际上创建了一个仅在该特定类型上存在的全新成员。
例如
public class Foo
{
public bool DoSomething() { return false; }
}
public class Bar : Foo
{
public new bool DoSomething() { return true; }
}
该方法在两种类型上都存在。当您使用反射并获取type的成员时Bar
,您实际上会发现2种方法DoSomething()
看起来完全相同。通过使用它,new
您可以有效地将实现隐藏在基类中,这样,当类派生自Bar
(在我的示例中)时,to的方法调用base.DoSomething()
转到Bar
not Foo
。
virtual / override告诉编译器这两个方法是相关的,并且在某些情况下,当您认为您正在调用第一个(虚拟)方法时,实际上调用第二个(重写)方法是正确的。这是多态性的基础。
(new SubClass() as BaseClass).VirtualFoo()
将调用子类的重写VirtualFoo()方法。
new告诉编译器您要向派生类中添加一个方法,该方法的名称与基类中的方法相同,但彼此之间没有关系。
(new SubClass() as BaseClass).NewBar()
将调用BaseClass的NewBar()方法,而:
(new SubClass()).NewBar()
将调用子类的NewBar()方法。
我的解释版本来自使用属性来帮助理解差异。
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
具有2个 GetSomething
属性,因为它实际上具有2个版本的属性Foo
“ s”和Bar
“ s”,并且要知道要使用哪个版本,c#会“拾取”当前类型的属性。
如果要使用Bar的版本,则应使用替代或Foo foo
替代。
Bar bar
仅有1个,因为它想要的全新行为GetSomething
。
不使用任何方法标记方法意味着:使用对象的编译类型而不是运行时类型(静态绑定)来绑定此方法。
用方法标记方法virtual
:使用对象的运行时类型而不是编译时间类型(动态绑定)绑定此方法。
virtual
用override
派生类标记基类方法意味着:这是要使用对象的运行时类型进行绑定的方法(动态绑定)。
在派生类中标记具有一个基类virtual
方法的方法new
是:这是一个新方法,它与基类中具有相同名称的方法没有关系,并且应使用对象的编译时类型(静态绑定)进行绑定。
virtual
在派生类中未标记基类方法意味着:该方法被标记为new
(静态绑定)。
标记方法abstract
意味着:该方法是虚拟的,但是我不会为其声明一个主体,并且它的类也是抽象的(动态绑定)。
new
创建具有相同名称的新成员并使原始成员隐藏,同时override
扩展了继承成员的实现”