我不确定什么看起来更好,或者我什么时候在抽象类和属性中使用,或何时使用非抽象属性。我将尝试做一个简单的例子。假设我有这个:
abstract class Human
{
public GenderType Gender { get; set; }
public string Name { get; set; }
public Date Born { get; set; }
public bool IsNerd { get; set; }
abstract public void Speak();
abstract public void Sleep();
abstract public void AnoyingPeopleOnStackOverflow();
//... so on
}
class Peter : Human
{
//Peter is special, he got a second name
//But thats all, everything else is the same as like on other humans
public string SecondName { get; set; }
//...override abstract stuff
}
这样好吗?据我所知,如果我不想覆盖它,我不必使用抽象属性。在这种情况下,没关系,只有Speak
,Sleep
等方法应该是抽象的。
现在,如果可以,我何时或应该使用抽象属性?
答案 0 :(得分:71)
如果没有默认实现,并且派生类必须实现它,请使用抽象属性。
如果在基类中有实现但希望允许覆盖,请使用虚拟属性。
使用override
关键字覆盖成员。如果成员不应再次被覆盖,请将该成员标记为sealed override
。
如果您不希望覆盖该属性,请不要将该属性标记为abstract
或virtual
。
使用new
关键字隐藏非抽象的非虚拟成员(这不是一个好主意)。
How to: Define Abstract Properties
我发现抽象属性经常出现在设计中,这意味着它们将具有特定于类型的逻辑和/或副作用。您基本上是在说,“这是一个所有子类必须具有的数据点,但我不知道如何实现它”。 然而,可能不需要包含大量逻辑和/或引起副作用的属性。这是一个重要的考虑因素,尽管没有固定的正确/错误的方法。
请参阅:
就个人而言,我发现我经常使用抽象方法但很少使用抽象属性。
答案 1 :(得分:27)
我知道我希望他们做什么,我不在乎他们是怎么做的:接口。
我知道我希望他们做什么,我不在乎他们是如何做的,但我对他们将如何(或至少大多数人)做其他事情有着坚定的想法:抽象类。
我知道我希望他们做什么,以及他们中的大多数人会这样做:具有虚拟成员的具体课程。
您可以使用其他案例,例如一个没有抽象成员的抽象类(你不能拥有一个实例,但是它提供了什么功能,它完全提供),但是它们通常是罕见的,因为特定的层次结构为一个给定的干净和公然提供了它问题
(顺便说一下,我不认为彼得是一种人类,但每个彼得都是人类的一个实例,恰好被称为彼得。以这种方式挑选示例代码并不公平,但是当你在思考这类问题时,它比平常更为恰当。)
答案 2 :(得分:13)
抽象成员只是您必须覆盖的虚拟成员。您将此用于必须实现的内容,但不能在基类中实现。
如果你想创建一个虚拟属性,并希望它必须在继承你的类的类中被覆盖,那么你可以将它作为一个抽象属性。
如果你有一个动物类,它的呼吸能力不可能只是从它的动物信息来确定,但它是非常重要的东西:
public abstract class Animal {
public abstract bool CanBreathe { get; }
}
对于鱼和狗,实施方式会有所不同:
public class Dog : Animal {
public override bool CanBreathe { get { return !IsUnderWater; } }
}
public class Fish : Animal {
public override bool CanBreathe { get { return IsUnderWater; } }
}
答案 3 :(得分:4)
当所有子类具有以实现方法/属性时使用abstract。如果不需要每个子类来实现它,那么就不要使用它。
至于你的例子,如果每个人不需要SecondName
,那么就不需要在基类中创建一个抽象属性。另一方面,如果每个人都需要第二个名字,那么将其作为一个抽象的财产。
正确使用抽象属性的示例:
public class Car
{
public abstract string Manufacturer { get; }
}
public class Odyssey : Car
{
public override string Manufacturer
{
get
{
return "Honda";
}
}
}
public class Camry : Car
{
public override string Manufacturer
{
get
{
return "Toyota";
}
}
}
制作Maker
摘要是正确的,因为每辆汽车都有制造商,并且需要能够告诉用户该制造商是谁。
答案 4 :(得分:1)
在您希望类始终公开属性的地方使用抽象属性,但是您无法确定该属性的实现方式 - 将其留给/强制继承类执行此操作。
有一个示例here,其中抽象类名为Shape
,它公开了一个抽象的Area
属性。您无法在基类中实现Area
属性,因为区域的公式将针对每种类型的形状进行更改。所有形状都有一个区域(某种形状),因此所有形状都应该暴露属性。
您的实施本身看起来很好。试图为Human
想出一个抽象属性的明智例子,却想不出任何合理的事情。