|
| 1 | +# ECS0008: Use the Null-Conditional Operator for Event Invocations |
| 2 | + |
| 3 | +This rule is described in detail in [Effective C#: 50 Specific Ways to Improve your C#](https://www.oreilly.com/library/view/effective-c-50/9780134579290/). |
| 4 | + |
| 5 | +## Cause |
| 6 | + |
| 7 | +This rule is triggered when an event handler is invoked without using the null-conditional operator (`?.`), which can potentially lead to a `NullReferenceException` if there are no subscribers to the event. |
| 8 | + |
| 9 | + |
| 10 | +## Rule description |
| 11 | + |
| 12 | +When invoking events in C#, it is recommended to use the null-conditional operator to ensure that the event is only invoked if it has subscribers. This prevents potential runtime errors and makes the code more robust. This rule checks for patterns where the event handler is invoked directly or after a null check and suggests replacing them with the null-conditional operator. |
| 13 | + |
| 14 | +## How to fix violations |
| 15 | + |
| 16 | +Replace any `if` statement that checks if an event handler is `null` and then invokes the handler with the null-conditional operator. |
| 17 | + |
| 18 | +If the code uses an intermediate variable (e.g., `var handler = Updated;`), remove the variable and replace the `if` statement with the null-conditional operator directly on the event. |
| 19 | + |
| 20 | +## When to suppress warnings |
| 21 | + |
| 22 | +You can suppress warnings from this rule if you're confident that the event will always have subscribers at the time of invocation, or if you have special logic that must be executed before the event is invoked. |
| 23 | + |
| 24 | +## Example of a violation |
| 25 | + |
| 26 | +### Description |
| 27 | + |
| 28 | +Directly invoking the event handler or checking for null before invoking without using the null-conditional operator. |
| 29 | + |
| 30 | +### Code |
| 31 | + |
| 32 | +```csharp |
| 33 | +public class EventSource |
| 34 | +{ |
| 35 | + private EventHandler<int> Updated; |
| 36 | + private int counter; |
| 37 | + |
| 38 | + public void RaiseUpdates() |
| 39 | + { |
| 40 | + counter++; |
| 41 | + if (Updated != null) |
| 42 | + Updated(this, counter); |
| 43 | + } |
| 44 | +} |
| 45 | + |
| 46 | +public class EventSource |
| 47 | +{ |
| 48 | + private EventHandler<int> Updated; |
| 49 | + private int counter; |
| 50 | + |
| 51 | + public void RaiseUpdates() |
| 52 | + { |
| 53 | + counter++; |
| 54 | + var handler = Updated; |
| 55 | + if (handler != null) |
| 56 | + handler(this, counter); |
| 57 | + } |
| 58 | +} |
| 59 | +``` |
| 60 | + |
| 61 | +## Example of how to fix |
| 62 | + |
| 63 | +### Description |
| 64 | + |
| 65 | +Replace the direct invocation or the null check with the null-conditional operator. |
| 66 | + |
| 67 | +### Code |
| 68 | + |
| 69 | +```csharp |
| 70 | +public class EventSource |
| 71 | +{ |
| 72 | + private EventHandler<int> Updated; |
| 73 | + private int counter; |
| 74 | + |
| 75 | + public void RaiseUpdates() |
| 76 | + { |
| 77 | + counter++; |
| 78 | + Updated?.Invoke(this, counter); |
| 79 | + } |
| 80 | +} |
| 81 | +``` |
0 commit comments