抑制或避免警告 CA2214
Posted
技术标签:
【中文标题】抑制或避免警告 CA2214【英文标题】:Suppressing or avoiding Warning CA2214 【发布时间】:2014-09-10 12:35:00 【问题描述】:我有一种情况,我根据收到的数据创建了一个名为 EntryEvent
的对象。必须解析该数据。基本事件应该开始解析通过构造函数接收并提供给对象的数据。子类型知道如何解析该特定数据集。现在,在编译所述代码时,我收到警告 CA2214,它包含对虚拟方法的调用链。虽然产生不可预见的后果可能很糟糕,但我不知道如何获得所需的行为:解析接收到的事件,而无需从外部调用额外的“解析”方法。
有问题的代码是:
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
【问题讨论】:
你能给我们更多的背景信息吗?有多种方法可以解决这个问题,但不会导致问题,但哪种方法最好取决于上下文。想象一个不需要需要覆盖ParseEvent
的子类是否合理?每个子类实际上是否有一个静态方法,该方法被赋予数据,解析它,然后调用构造函数来获取已经解析的数据?
在您问题的代码中,ParseEvent()
可以是非虚拟的,仅为EntryEvent
定义,并直接从EntryEvent
的构造函数中调用。如果您的真实代码无法做到这一点,您能否更新您的问题以更好地说明您正在处理的场景?
@JonSkeet 该事件来自外部来源。每个子类都需要重写,因为每个子类都需要进行自己的解析。基类保存每个事件提供的一般数据。我的意图是强制特定事件的实现者实现解析器,而不是强制他实际调用它。我想要避免的是给实现者(即使是我)随机命名解析方法的选项,不管它是静态的还是非静态的,但也许我过度分析了它。
@private_meta:构造一个事件而不解析任何东西是否有意义,即使这主要用于测试?尚不清楚解析是否真的固有存在于事件对象中,或者它是否只是通常发生的情况。考虑制作获取原始数据的构造函数(即使它们只是私有/受保护的),而不是在构造函数中解析 in。如果有用的话,我可以举个例子。
@JonSkeet 构造函数中提供的数据是通过 c++ 设备库从设备获取事件数据的句柄,因此其目的是不必在事件之外进行设备处理。跨度>
【参考方案1】:
根据 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
/特殊值)这是我更喜欢的方法即使它更冗长。
【讨论】:
谢谢。至于 3),延迟加载不是一种选择,因为数据可能在需要时无法从源获得。当然,我想避免 1),因为我看到了潜在的问题。 2) 似乎是一种有效的折衷方案,尤其是将文档与开发人员必须实现的抽象方法相结合。我只是想避免子类的开发者忘记或忽略某些东西。 @private_meta with 2) 开发人员可能会忘记在他的类构造函数中调用 ParseEvent()。他的错,但您可以在访问属性时进行一些检查(至少在 DEBUG 构建中)。也许是一个工厂类和一个 Parse() 方法被那个调用......)以上是关于抑制或避免警告 CA2214的主要内容,如果未能解决你的问题,请参考以下文章
如何抑制“避免使用捆绑版的 Google Play 服务 SDK”警告?