C# 抑制或避免警告CA2214

C# 抑制或避免警告CA2214,c#,fxcop,C#,Fxcop,在这种情况下,我根据收到的数据创建一个名为EntryEvent的对象。必须对这些数据进行分析。基本事件应该启动对通过构造函数接收并提供给对象的数据的解析。子类型知道如何对特定数据集进行PAR。现在,当编译上述代码时,我得到警告CA2214,它包含一个虚拟方法的调用链。虽然产生不可预见的后果可能不好,但我不知道如何获得所需的行为:解析接收到的事件,而不必从外部调用额外的“Parse”方法 有关守则是: public abstract class BaseEvent { protected

在这种情况下,我根据收到的数据创建一个名为
EntryEvent
的对象。必须对这些数据进行分析。基本事件应该启动对通过构造函数接收并提供给对象的数据的解析。子类型知道如何对特定数据集进行PAR。现在,当编译上述代码时,我得到警告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
    }
}
根据MSDN(重点是我的):

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

因此,我认为您有以下选择(至少):

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

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

我不太喜欢这种方法,因为它增加了额外的复杂性,但是如果您的类层次结构太大(那么您觉得不能使用#1)或者延迟初始化(如#3所述)不适用,那么它可能是一种有效的解决方案。我还将考虑更改设计,以介绍一个工厂方法,该方法将调用每个完全构造的对象的PARSEEVER()。 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
以更精确、清晰和线程安全的方式执行相同的任务。当然,在现实中,你会有更多的字段/属性,解析可能会一次提供所有值(然后你只需要一个标志,每个字段上不需要
Nullable
/特殊值),这是我更喜欢的方法,即使它更详细。

你能给我们更多的上下文吗?有多种方法可以解决这个问题,但哪种方法最好取决于上下文。想象一个不需要重写
ParseEvent
的子类是否合理?每个子类是否真的有一个静态方法,该方法提供了数据,对其进行解析,然后调用获取已解析数据的构造函数?在您问题中的代码中,
ParseEvent()
可以是非虚拟的,仅为
EntryEvent
定义,并直接从
EntryEvent
的构造函数调用。如果你的真实代码无法做到这一点,你能更新你的问题以更好地说明你正在处理的场景吗?@JonSkeet事件来自外部来源。每个子类都需要重写,因为每个子类都需要自己进行解析。基类保存每个事件提供的常规数据。我的意图是强迫特定事件的实现者实现解析器,而不是强迫他实际调用它。我想避免的是给实现者(即使是我)一个选项,让他随意命名解析方法,不管它是静态的还是非静态的,但可能是我对它进行了过度分析。@private\u meta:在不解析任何东西的情况下构造一个事件有意义吗,即使这主要是为了测试?目前还不清楚解析是否真的是事件对象的存在所固有的,或者它是否只是通常发生的事情。考虑构造构造函数(即使它们只是私有的/保护的),而不是在构造函数中进行解析。我可以给出一个例子,如果这是有用的。@ JOnScET在构造函数中提供的数据是一个句柄,通过一个C++设备库从设备中获取事件数据,因此目的是不必在事件之外进行设备处理。对于3),延迟加载不是一个选项,因为数据在需要时可能无法从源中获得。我当然想避免,因为我看到了潜在的问题。2) 这似乎是一个有效的折衷方案,尤其是将文档与开发人员必须实现的抽象方法相结合。我只是想避免子类的开发人员能够忘记或忽略某些东西。@private_meta with 2)开发人员可能会忘记在其类构造函数中调用ParseEvent()。但在访问属性时(至少在调试版本中)可以进行一些检查。可能是一个工厂类和一个Parse()方法,由它调用…)