No Virtual Field Like Event
ID |
csharp.no_virtual_field_like_event |
Severity |
high |
Remediation Complexity |
medium |
Remediation Risk |
low |
Remediation Effort |
medium |
Resource |
Code Smell |
Language |
CSharp |
Tags |
code_smell, events, inheritance |
Description
Reports field-like events declared virtual. A field-like event is written without an
add/remove accessor block, so the compiler generates the backing delegate field and the
accessors for it. Events with explicit accessors are not reported, and neither are
non-virtual or abstract events.
Rationale
The delegate field behind a field-like event is private to the class that declares it. When a derived class overrides the event, it gets a second backing field of its own, and the two fields are unrelated. Handlers added through a base-typed reference go on the base list; handlers added through a derived-typed reference go on the derived list. Raising the event from the base class walks only the base list, raising it from the derived class only the derived list — so some subscribers are silently never called, and which ones depends on the static type at each subscription site rather than on anything visible at the declaration.
using System;
public class Publisher
{
public virtual event EventHandler Started; // FLAW - overriding splits the handler list
public virtual event EventHandler Guarded // OK - explicit accessors, an override can cooperate
{
add { guarded += value; }
remove { guarded -= value; }
}
public event EventHandler Plain; // OK - not virtual
private EventHandler guarded;
}
Remediation
Drop the virtual modifier and give derived classes a protected virtual OnStarted(…)
method that raises the event; overriding that method is the standard extension point and
leaves a single invocation list. If the event itself really has to be overridable, write
explicit add/remove accessors so the storage is under the author’s control and an override
can delegate to the base implementation.