抑制或避免警告CA2214

本文关键字:警告 CA2214 | 更新日期: 2023-09-27 18:21:32

我有一种情况,我从收到的数据中创建了一个名为EntryEvent的对象。必须对该数据进行解析。基本事件应该启动对通过构造函数接收并提供给对象的数据的解析。子类型知道如何解析特定的数据集。现在,当编译所述代码时,我得到警告CA2214,它包含对虚拟方法的调用链。虽然产生不可预见的后果可能很糟糕,但我不知道如何获得所需的行为:解析接收到的事件,而不必从外部调用额外的"Parse"方法。

有问题的代码是:

public abstract class BaseEvent
{
    protected BaseEvent(object stuff)
    {
        this.ParseEvent();
    }
    protected abstract void ParseEvent();
}
public class EntryEvent : BaseEvent
{
    public EntryEvent( object stuff )
        : base( stuff )
    {
    }
    protected override void ParseEvent()
    {
        // Parse event
    }
}

抑制或避免警告CA2214

根据MSDN(重点是我的):

当调用虚拟方法时,直到运行时才会选择执行该方法的实际类型。当构造函数调用虚拟方法时,调用该方法的实例的构造函数可能尚未执行

所以在我看来,你有这些选择(至少):

1) 不要禁用该警告,而是为记录其预期行为的特定类抑制该消息(假设您在处理此类场景时格外小心)。如果它被限制在一个非常可控的环境中的几个类,那也没那么糟糕(毕竟…警告不是错误,它们可能会被忽略)。

2) 从基类构造函数中删除该虚拟方法调用,但保留abstract方法声明。开发人员必须实现这样的方法,并且要在构造函数中调用它,他们需要将自己的类标记为sealed。最后在类/方法文档中添加一个地方,即该方法必须在其构造函数内调用,并且其类必须是sealed才能调用。它们可以忘记调用,但您可以在访问属性或方法时添加(对于DEBUG构建)检查(例如,作为类接口的一部分,强制设置特定标志)。如果他们忘记设置标志或忘记调用方法,则将引发异常("此对象尚未构建,必须在派生类构造函数中调用ParseEvent()。")。

我不太喜欢这个方法,因为它增加了额外的复杂性,但如果你的类层次结构太大(然后你觉得你不能使用#1)或懒惰初始化(如#3所述)不适用,那么它可能是一个工作的解决方案。我还考虑更改设计,引入一个工厂方法,该方法将为每个完全构建的对象调用ParseEvent()。

3) 稍微改变一下你的设计:将解析推迟到需要的时候。例如:

public abstract class BaseEvent
{
    public DateTime TimeStamp
    {
        get
        {
            if (_timestamp == null)
                ParseEvent();
            return _timestamp.Value;
        }
        protected set { _timestamp = value; }
    }
    protected BaseEvent(object stuff)
    {
    }
    protected abstract void ParseEvent();
    private DateTime? _timestamp;
}

最后一个示例仅用于说明目的,您可能希望使用Lazy<T>以更精确、清晰和线程安全的方式执行相同的任务。当然,在现实中,你会有更多的字段/属性,解析可能会在一个镜头中提供所有值(然后你只需要一个标志,不需要在每个字段上使用Nullable/特殊值)这是我更喜欢的方法,即使它更详细。