|
215 | 215 |
|
216 | 216 | - **Use `var` only for complex types when type is apparent from context** |
217 | 217 | ```csharp |
218 | | - var control = new Button(); // OK - type is obvious |
219 | | - var items = GetComplexCollection(); // OK - long type name |
| 218 | + var control = new Button(); // OK - type is obvious, but better is: |
| 219 | + Button control = new(); // Preferred |
| 220 | + |
| 221 | + // OK - long type name |
| 222 | + var items = GetComplexCollectionWithRidiculousLongTypeName(); |
220 | 223 | int primitiveValue = 42; // Required for primitives |
221 | 224 | ``` |
222 | 225 |
|
|
239 | 242 | ```csharp |
240 | 243 | private static readonly int s_defaultBorderWidth = 1; |
241 | 244 | ``` |
| 245 | +An exception to this rule is when the field is attributed with `[ThreadStatic]`, in which case the prefix should be `t_`: |
| 246 | + ```csharp |
| 247 | + [ThreadStatic] |
| 248 | + private static int t_threadLocalValue; |
| 249 | + ``` |
242 | 250 |
|
243 | 251 | - **Prefix private/internal instance fields with `_`** (suggestion level) |
244 | 252 | ```csharp |
|
286 | 294 | private bool IsVisible() => Visible && Parent?.Visible == true; |
287 | 295 | ``` |
288 | 296 |
|
289 | | -- For longer expressions, use line breaks with proper alignment: |
| 297 | +For longer expressions, use line breaks with proper alignment: |
290 | 298 | ```csharp |
291 | 299 | internal int SomeFooIntegerProperty => |
292 | 300 | _someFooIntegerProperty; |
|
295 | 303 | size.Width > 0 |
296 | 304 | && size.Height > 0; |
297 | 305 | ``` |
| 306 | +**IMPORTANT** |
| 307 | + |
| 308 | +In C#, `public Foo FooInstance => new Foo();` and `public Foo FooInstance { get; } = new Foo();` are NOT interchangeable. |
| 309 | + |
| 310 | +* The first is an expression-bodied property that returns a new value each time it is accessed. |
| 311 | +* The second is a read-only auto-property with initializer that returns the same value every time, created once. |
| 312 | + |
| 313 | +When editing, generating, or suggesting C# properties, always maintain the original intent: |
| 314 | + |
| 315 | +* Use an expression-bodied property (`=>`) for computed or dynamic values. |
| 316 | +* Use an auto-property with initializer (`{ get; } = ...`) for stored, initialized-once values. |
| 317 | + |
| 318 | +Never "correct" or convert one style to the other unless you are certain the semantic behavior is intended to change because it was wrong with 100% confidence to begin with. If you encounter a case, where you have a expression-bodied property that returns a new instance, and you encounter this in a code review, you should add a comment explaining why this is intended, and that it is not a mistake. |
298 | 319 |
|
299 | 320 | ### 1.5 Error Handling and Argument Validation |
300 | 321 |
|
|
345 | 366 | - **Handle platform-specific code appropriately** |
346 | 367 | ```csharp |
347 | 368 | [SupportedOSPlatform("windows")] |
348 | | - private void WindowsSpecificMethod() { ... } |
| 369 | + private void WindowsSpecificMethod() |
| 370 | + { |
| 371 | + ... |
| 372 | + } |
349 | 373 | ``` |
350 | 374 |
|
351 | 375 | - **Use proper disposal patterns** |
352 | | - ```csharp |
353 | | - using var brush = new SolidBrush(Color.Red); // Simple using for single resources |
354 | | - |
355 | | - // Traditional using for complex scenarios |
356 | | - using (Graphics g = CreateGraphics()) |
357 | | - { |
358 | | - // Drawing operations |
359 | | - } |
360 | | - ``` |
| 376 | +Prefer the modern C# "using declaration" syntax (using var ...) over the traditional using statement block. |
| 377 | +Use: |
| 378 | + |
| 379 | +```csharp |
| 380 | +using var brush = backColor.GetCachedSolidBrushScope(); |
| 381 | +``` |
| 382 | + |
| 383 | +instead of: |
| 384 | + |
| 385 | +```csharp |
| 386 | +using (SolidBrushCache.Scope brush = backColor.GetCachedSolidBrushScope()) |
| 387 | +{ |
| 388 | + // ... |
| 389 | +} |
| 390 | +``` |
| 391 | + |
| 392 | +This makes code more concise, reduces nesting, and improves readability. Only use the older style if you need to limit the scope of the variable to a smaller section within a larger method, or when the using var pattern is not supported. **Note**, that if you use `using` with the type name over `var` for new instances that you can omit the type name after the `new` like: |
| 393 | + |
| 394 | +```csharp |
| 395 | +using Pen focusPen = new(focusColor) // Use 'using' with type name and omit type after 'new' |
| 396 | +{ |
| 397 | + Width = 1.0f, |
| 398 | + DashStyle = DashStyle.Dot |
| 399 | +}; |
| 400 | +``` |
361 | 401 |
|
362 | 402 | ### 1.8 XML Documentation Standards |
363 | 403 |
|
|
402 | 442 | ### 1.10 Magic Numbers |
403 | 443 |
|
404 | 444 | - **Avoid magic numbers**: Use named constants or enums instead of hard-coded values. This improves readability and maintainability. |
| 445 | + |
405 | 446 | ```csharp |
406 | 447 | // Avoid magic numbers |
407 | 448 | const int MaxItems = 100; |
|
451 | 492 | } |
452 | 493 | ``` |
453 | 494 |
|
| 495 | + Note: If a code line for which these empty-line rules apply has a comment on top of it, the empty line should be placed before the comment, if there isn't one. And of course, NEVER comment that an empty lines need to be inserted at a spot, which would defeat the purpose of the empty line. |
| 496 | + |
| 497 | + |
454 | 498 | ### 1.12 Refactoring of existing comments |
455 | 499 |
|
456 | 500 | - **Refactor existing comments**: When refactoring code, also consider updating or removing outdated comments. Comments should accurately reflect the current state of the code and its purpose. Avoid/rephrase inappropriate comments or microaggressions. |
|
0 commit comments