Warning: file_get_contents(/data/phpspider/zhask/data//catemap/2/csharp/312.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
C# 我应该使方法虚拟化还是抽象化?_C#_.net_Class Design - Fatal编程技术网

C# 我应该使方法虚拟化还是抽象化?

C# 我应该使方法虚拟化还是抽象化?,c#,.net,class-design,C#,.net,Class Design,我有一个抽象类,它自己进行内部验证。它还有另一种方法,允许子类进行额外的验证检查。目前,我已经将方法抽象化了 protected abstract bool ValidateFurther(); 然而,我看到相当多的子类被迫重写它,只是为了返回true。我正在考虑把这个方法变成虚拟的 protected virtual bool ValidateFurther() => true; 假设在抽象类中验证会很好,这不好吗?我担心子类可能不会注意到它,甚至在需要时也不会覆盖它。这里哪种方法更

我有一个抽象类,它自己进行内部验证。它还有另一种方法,允许子类进行额外的验证检查。目前,我已经将方法
抽象化了

protected abstract bool ValidateFurther();
然而,我看到相当多的子类被迫重写它,只是为了返回
true
。我正在考虑把这个方法变成虚拟的

protected virtual bool ValidateFurther() => true;

假设在抽象类中验证会很好,这不好吗?我担心子类可能不会注意到它,甚至在需要时也不会覆盖它。这里哪种方法更合适?

您可以在设计中添加另一层

public abstract class Base
{
    protected abstract bool ValidateFurther();
}

public abstract class BaseWithValidation : Base
{
    protected override bool ValidateFurther() => true;
}
如果继承类的重要子集只返回true,则可以使用
BaseWithValidation
,以避免到处重复代码;对于任何其他内容,请使用
Base

  • abstract
    方法意味着您只需要定义要遵循的行为,并让子类执行实现
  • virtual
    method表示您定义了一个具有初始实现的方法,但允许重写

所以,也许你可以解释你的上下文,然后我们可以讨论它

可以使方法
虚拟化
,并定义一个返回
true
的默认实现

protected virtual bool ValidateFurther() => true;
abstract
virtual
之间的区别在于,抽象方法只定义方法的签名,而实现由派生类实现(类似于接口)。所有子类都需要实现抽象方法的逻辑。有关更多详细信息,请参见

另一方面,
Virtual
要求您实现逻辑,如果需要,您可以
覆盖该方法以添加/扩展逻辑。而且,由于您有默认逻辑,您的子类/派生类不需要重写它。有关更多详细信息,请参见

基本上,可以将该方法实现为
virtual
返回true默认情况下

仅供参考:在C#8中,您可以在接口中使用默认实现 如果这个类(及其所有派生类)的用途并不总是需要验证,那么您应该使用
virtual
,否则
abstract

换句话说,验证是这门课目的的基石吗?(是=抽象,否=虚拟)

我怀疑
virtual
在这里是更好的方法,但这并不是你所认为的原因。这个答案的其余部分详细说明了为什么你的推理不是决定因素,以及什么才是真正的决定因素


你的推理 我看到相当多的子类被迫重写它以返回true

我怀疑你屈服于程序员的反射:“我看到这种重复,必须编写代码来避免这种重复!”

虽然这通常是一种很好的方法,但当您开始将其应用于碰巧相同的事物而不是表达相同的功能目的时,它也可能被误用

我倾向于使用以下示例来说明这一点:

public class Book
{
    public string Title { get; set; }
    public DateTime CreatedOn { get; set; }
}

public class EmployeeJob
{
    public string Title { get; set; }
    public DateTime CreatedOn { get; set; }
}
抽象
CreatedOn
属性肯定有价值,因为这些实体都是经过审核的数据实体。
CreatedOn
属性是被审计实体的一部分,它在
Book
EmployeeJob
中的存在都源于这些类都是被审计实体

如果对已审核实体进行了更改(例如,它们不再跟踪创建日期),则该更改需要自动保留到所有已审核实体。当您使用共享逻辑时,这会自动发生

但是,
标题
是否需要抽象为共享逻辑?不,这里没有功能重叠。是的,这些属性具有相同的名称和类型,但它们没有任何共同的逻辑。他们现在正好是平等的,但是他们之间没有联系

如果对一个
标题
属性进行了更改(例如,它现在成为工作标题表的
Guid
FK),则该更改不会自动反映在另一个属性上(例如,书名仍然只是一个字符串)。使用共享逻辑实现这些
Title
属性实际上会导致问题,而不是解决问题

简言之:有时程序员寻找的模式比他们需要的更多。或者如果你允许我


决定因素 我正在考虑把这个方法虚拟化

您是将其抽象化还是虚拟化取决于一个特定的考虑因素(不是干巴巴的,如上所述):您希望提供默认实现,还是希望强制每个使用者(即派生类)自己评估此方法的实现

这两种方法在客观上都不比另一种好,这是一个最适合你当前情况的问题

我看到相当多的子类被迫重写它以返回true

我由此推断,您基本上跳过了这些类中的验证,因此在这种情况下,我会选择
虚拟
方法,因为此类(及其所有派生类)的目的并不总是需要验证(同样,这是基于您的解释的我的解释)


换句话说,验证是这门课目的的基石吗?(是=抽象,否=虚拟)。你没有指定你的类或它的用途,所以我不能进行最后的调用。

如果你想强制派生类实现某些东西,我们不能在没有更多上下文的情况下真正回答这个问题,最好将它命名为
basewithnotoughtValidation
,或者,在