什么时候应该将类成员声明为虚拟(C#)/可重写(VB.NET)?
我为什么不选择摘要?声明类成员为虚拟成员有哪些限制?只能将方法声明为虚拟方法吗?
解决方案
回答
如果要在基类中为其实现,则将其虚拟化,否则将其抽象化。
是的,只能将方法声明为虚拟方法。
回答
如果我们不想在基类中定义任何实现,并且希望强制在任何派生类中定义它,则可以使用abstract。如果要提供可以被派生类覆盖的默认实现,则将其定义为虚拟。
是的,只有方法可以是虚拟的。
回答
抽象意味着我们不能提供默认的实现。反过来,这意味着所有子类都必须提供abstract方法的实现才能实例化(具体)。
我不确定我们所说的"限制"是什么意思,因此无法回答这一点。
可以将属性声明为虚拟属性,但我们也可以在概念上将它们视为方法。
回答
如果存在基本实现,则应将成员声明为虚拟成员,但是有可能在子类中重写该功能。也可以使用Virtual而不是Abstract来允许方法实现是可选的(即,基本实现是一个空方法)
将成员设置为虚拟成员时没有限制,但是虚拟成员比非虚拟方法要慢。
方法和属性都可以标记为虚拟。
回答
首先,我将回答我们第二个问题。只能将方法声明为虚拟方法。
当我们想要基类中的某些默认功能时,可以选择虚拟而不是抽象,但是我们希望保留由继承自基类的类覆盖此功能的选项。
举些例子:
如果要实现Shape类,则可能会有一个名为getArea()的方法,该方法返回形状的区域。在这种情况下,Shape类中的getArea()方法没有默认行为,因此我们可以将其实现为抽象。将方法实现为抽象将阻止我们实例化Shape对象。
另一方面,如果实现Dog类,则在这种情况下可能想要实现Bark()方法,可能希望实现默认的吠叫声并将其放入Dog类中,而某些继承的类(如Chiwawa类可能希望重写此方法并实现特定的吠叫声。在这种情况下,树皮方法将被实现为虚拟方法,我们将能够实例化Dogs和Chiwawas。
回答
抽象方法或者属性(可以是虚拟的也可以是抽象的)只能在抽象类中声明并且不能具有主体,即我们不能在抽象类中实现它。
虚拟方法或者属性必须具有主体,即我们必须提供实现(即使主体为空)。
如果有人想使用抽象类,则他将必须实现一个继承自该类的类,并明确实现抽象方法和属性,但可以选择不覆盖虚拟方法和属性。
范例:
using System; using C=System.Console; namespace Foo { public class Bar { public static void Main(string[] args) { myImplementationOfTest miot = new myImplementationOfTest(); miot.myVirtualMethod(); miot.myOtherVirtualMethod(); miot.myProperty = 42; miot.myAbstractMethod(); } } public abstract class test { public abstract int myProperty { get; set; } public abstract void myAbstractMethod(); public virtual void myVirtualMethod() { C.WriteLine("foo"); } public virtual void myOtherVirtualMethod() { } } public class myImplementationOfTest : test { private int _foo; public override int myProperty { get { return _foo; } set { _foo = value; } } public override void myAbstractMethod() { C.WriteLine(myProperty); } public override void myOtherVirtualMethod() { C.WriteLine("bar"); } } }
回答
Windows窗体在这里有一个陷阱。
如果我们希望可以从中继承Control / UserControl,即使我们在基类中没有逻辑,也不要抽象它,因为否则我们将无法在派生类中使用Designer:
http://www.urbanpotato.net/default.aspx/document/2001
回答
我们所提出的问题更多与风格有关,而不是技术方面。我认为这本书
http://www.amazon.com/Framework-Design-Guidelines-Conventions-Development/dp/0321246756
围绕问题和许多其他问题进行了精彩的讨论。
回答
我亲自将大多数方法和属性标记为虚拟。我使用代理和大量延迟加载,因此我不必担心以后再进行更改。