关于.net:什么时候应该将类成员声明为虚拟(C#)/ Overridable(VB.NET)?

关于.net:什么时候应该将类成员声明为虚拟(C#)/ Overridable(VB.NET)?

When should a class member be declared virtual (C#)/Overridable (VB.NET)?

为什么我不选择抽象? 声明类成员虚拟有哪些限制? 只能将方法声明为虚拟?


抽象方法或属性(都可以是虚拟的或抽象的)只能在抽象类中声明,并且不能有一个主体,即你不能在抽象类中实现它。

虚方法或属性必须具有正文,即必须提供实现(即使正文为空)。

如果有人想要使用您的抽象类,他将不得不实现一个继承自它的类并显式实现抽象方法和属性,但可以选择不覆盖虚拟方法和属性。

例如:

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
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
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");
        }
    }
}

如果您不想在基类中定义任何实现并希望强制在任何派生类中定义它,则可以使用abstract。如果要提供可由派生类覆盖的默认实现,请将其定义为虚拟。

是的,只有方法可以是虚拟的。


如果存在基本实现,则应将成员声明为虚拟成员,但有可能在子类中重写该功能。也可以使用Virtual而不是abstract来允许方法实现是可选的(即,基本实现是一个空方法)

将成员设置为虚拟时没有限制,但虚拟成员比非虚拟方法慢。

方法和属性都可以标记为虚拟。


这里有一个问题需要注意Windows Forms。

如果你想要一个可以继承的Control / UserControl,即使你在基类中没有逻辑,你也不希望它是抽象的,因为否则你将无法在派生类中使用Designer:
http://www.urbanpotato.net/default.aspx/document/2001


我个人将大多数方法和属性标记为虚拟。我使用代理和延迟加载很多,所以我不想担心以后更改的东西。


你的问题与风格有关,而不是技术问题。我认为这本书
http://www.amazon.com/Framework-Design-Guidelines-Conventions-Development/dp/0321246756
围绕你的问题和很多其他人进行了很好的讨论。


首先,我将回答你的第二个问题。只有方法可以声明为虚拟。
当您需要基类中的某些默认功能时,可以选择虚拟而不是抽象,但是您希望保留通过从基类继承的类来覆盖此功能的选项。
举些例子:

如果你正在实现Shape类,你可能会有一个名为getArea()的方法返回你的形状区域。在这种情况下,Shape类中的getArea()方法没有默认行为,因此您可以将其实现为抽象。将方法实现为抽象将阻止您实例化Shape对象。

另一方面,如果你实现类Dog,你可能想要在这种情况下实现方法Bark(),你可能想要实现一个默认的吠声并把它放在Dog类中,而一些继承类,比如Chiwawa类可能希望覆盖此方法并实现特定的吠叫声。在这种情况下,方法bark将实现为虚拟,您将能够实例化Dogs以及Chiwawas。


摘要表示您无法提供默认实现。这反过来意味着所有子类必须提供抽象方法的实现,以便可实例化(具体)。

我不确定你的'限制'是什么意思,所以无法回答这一点。

可以将属性声明为虚拟属性,但您也可以在概念上将它们视为方法。


如果你想在你的基类中给它一个实现,你就把它变成虚拟的,如果你不这样做,你就把它变成抽象的。

是的,只有方法可以声明为虚拟。


推荐阅读