From f58733bc106868aec85b1e425995f1b081c73b1b Mon Sep 17 00:00:00 2001 From: Genevieve Warren <24882762+gewarren@users.noreply.github.com> Date: Tue, 30 Apr 2024 21:29:20 -0700 Subject: [PATCH] revamp best practices article --- .../exception-handling-statements.md | 2 +- docs/csharp/nullable-references.md | 2 +- .../code-analysis/quality-rules/ca1065.md | 70 ++--- .../code-analysis/quality-rules/ca2200.md | 2 +- .../code-analysis/quality-rules/ca2208.md | 4 +- .../code-analysis/quality-rules/index.md | 64 ++--- .../snippets/csharp/all-rules/ca2200.cs | 6 +- .../best-practices-for-exceptions.md | 247 +++++++++++------- .../exceptions/how-to-use-finally-blocks.md | 2 +- .../best-practices/csharp/Project.csproj | 10 + .../snippets/best-practices/csharp}/source.cs | 41 +-- .../csharp/Project.csproj | 10 + .../csharp}/source2.cs | 2 - .../Exception.Throwing/CS/throw.cs | 48 ++-- .../dg_exceptionDesign/cs/example1.cs | 232 ---------------- .../dg_exceptionDesign/cs/example2.cs | 9 +- 16 files changed, 276 insertions(+), 475 deletions(-) create mode 100644 docs/standard/exceptions/snippets/best-practices/csharp/Project.csproj rename {samples/snippets/csharp/VS_Snippets_CLR/conceptual.exception.handling/cs => docs/standard/exceptions/snippets/best-practices/csharp}/source.cs (69%) create mode 100644 docs/standard/exceptions/snippets/how-to-use-finally-blocks/csharp/Project.csproj rename {samples/snippets/csharp/VS_Snippets_CLR/CodeTryCatchFinallyExample/CS => docs/standard/exceptions/snippets/how-to-use-finally-blocks/csharp}/source2.cs (97%) delete mode 100644 samples/snippets/csharp/VS_Snippets_CLR/dg_exceptionDesign/cs/example1.cs diff --git a/docs/csharp/language-reference/statements/exception-handling-statements.md b/docs/csharp/language-reference/statements/exception-handling-statements.md index 8f964cf600603..3fb5c457f8e18 100644 --- a/docs/csharp/language-reference/statements/exception-handling-statements.md +++ b/docs/csharp/language-reference/statements/exception-handling-statements.md @@ -33,7 +33,7 @@ The `throw` statement throws an exception: In a `throw e;` statement, the result of expression `e` must be implicitly convertible to . -You can use the built-in exception classes, for example, or . .NET also provides the helper methods to throw exceptions in certain conditions: and . You can also define your own exception classes that derive from . For more information, see [Creating and throwing exceptions](../../fundamentals/exceptions/creating-and-throwing-exceptions.md). +You can use the built-in exception classes, for example, or . .NET also provides the following helper methods to throw exceptions in certain conditions: and . You can also define your own exception classes that derive from . For more information, see [Creating and throwing exceptions](../../fundamentals/exceptions/creating-and-throwing-exceptions.md). Inside a [`catch` block](#the-try-catch-statement), you can use a `throw;` statement to re-throw the exception that is handled by the `catch` block: diff --git a/docs/csharp/nullable-references.md b/docs/csharp/nullable-references.md index 19a586096bd71..c7d617de72257 100644 --- a/docs/csharp/nullable-references.md +++ b/docs/csharp/nullable-references.md @@ -166,7 +166,7 @@ name!.Length; Nullable reference types and nullable value types provide a similar semantic concept: A variable can represent a value or object, or that variable might be `null`. However, nullable reference types and nullable value types are implemented differently: nullable value types are implemented using , and nullable reference types are implemented by attributes read by the compiler. For example, `string?` and `string` are both represented by the same type: . However, `int?` and `int` are represented by `System.Nullable` and , respectively. -Nullable reference types are a compile time feature. That means it's possible for callers to ignore warnings, intentionally use `null` as an argument to a method expecting a non nullable reference. Library authors should include runtime checks against null argument values. The is the preferred option for checking a parameter against null at run time. +Nullable reference types are a compile time feature. That means it's possible for callers to ignore warnings, intentionally use `null` as an argument to a method expecting a non nullable reference. Library authors should include run-time checks against null argument values. The is the preferred option for checking a parameter against null at run time. > [!IMPORTANT] > Enabling nullable annotations can change how Entity Framework Core determines if a data member is required. You can learn more details in the article on [Entity Framework Core Fundamentals: Working with Nullable Reference Types](/ef/core/miscellaneous/nullable-reference-types). diff --git a/docs/fundamentals/code-analysis/quality-rules/ca1065.md b/docs/fundamentals/code-analysis/quality-rules/ca1065.md index 31c1c468cc743..35dd7c75ad0c9 100644 --- a/docs/fundamentals/code-analysis/quality-rules/ca1065.md +++ b/docs/fundamentals/code-analysis/quality-rules/ca1065.md @@ -29,99 +29,83 @@ A method that is not expected to throw exceptions throws an exception. Methods that are not expected to throw exceptions can be categorized as follows: -- Property Get Methods - -- Event Accessor Methods - -- Equals Methods - -- GetHashCode Methods - -- ToString Methods - -- Static Constructors - +- Property get methods +- Event accessor methods +- Equals methods +- GetHashCode methods +- ToString methods +- Static constructors - Finalizers - -- Dispose Methods - -- Equality Operators - -- Implicit Cast Operators +- Dispose methods +- Equality operators +- Implicit cast operators The following sections discuss these method types. -### Property Get Methods +### Property get methods Properties are basically smart fields. Therefore, they should behave like a field as much as possible. Fields don't throw exceptions and neither should properties. If you have a property that throws an exception, consider making it a method. The following exceptions can be thrown from a property get method: - and all derivatives (including ) - - and all derivatives - - (only from indexed get) - - (only from indexed get) -### Event Accessor Methods +### Event accessor methods Event accessors should be simple operations that don't throw exceptions. An event should not throw an exception when you try to add or remove an event handler. The following exceptions can be thrown from an event accessor: - and all derivatives (including ) - - and all derivatives - - and derivatives -### Equals Methods +### Equals methods The following **Equals** methods should not throw exceptions: - - - -An **Equals** method should return `true` or `false` instead of throwing an exception. For example, if Equals is passed two mismatched types it should just return `false` instead of throwing an . +An `Equals` method should return `true` or `false` instead of throwing an exception. For example, if `Equals` is passed two mismatched types, it should just return `false` instead of throwing an . -### GetHashCode Methods +### GetHashCode methods -The following **GetHashCode** methods should usually not throw exceptions: +The following `GetHashCode` methods should usually not throw exceptions: - - - -**GetHashCode** should always return a value. Otherwise, you can lose items in the hash table. +`GetHashCode` should always return a value. Otherwise, you can lose items in the hash table. -The versions of **GetHashCode** that take an argument can throw an . However, **Object.GetHashCode** should never throw an exception. +The versions of `GetHashCode` that take an argument can throw an . However, `Object.GetHashCode` should never throw an exception. -### ToString Methods +### ToString methods -The debugger uses to help display information about objects in string format. Therefore, **ToString** should not change the state of an object, and it shouldn't throw exceptions. +The debugger uses to help display information about objects in string format. Therefore, `ToString` should not change the state of an object, and it shouldn't throw exceptions. -### Static Constructors +### Static constructors Throwing exceptions from a static constructor causes the type to be unusable in the current application domain. You should have a good reason (such as a security issue) for throwing an exception from a static constructor. ### Finalizers -Throwing an exception from a finalizer causes the CLR to fail fast, which tears down the process. Therefore, throwing exceptions in a finalizer should always be avoided. +Throwing an exception from a finalizer causes the CLR to fail fast, which tears down the process. Therefore, avoid throwing exceptions in a finalizer. -### Dispose Methods +### Dispose methods -A method should not throw an exception. Dispose is often called as part of the cleanup logic in a `finally` clause. Therefore, explicitly throwing an exception from Dispose forces the user to add exception handling inside the `finally` clause. +A method should not throw an exception. `Dispose` is often called as part of the cleanup logic in a `finally` clause. Therefore, explicitly throwing an exception from `Dispose` forces the user to add exception handling inside the `finally` clause. -The **Dispose(false)** code path should never throw exceptions, because Dispose is almost always called from a finalizer. +The `Dispose(false)` code path should never throw exceptions, because `Dispose` is almost always called from a finalizer. -### Equality Operators (==, !=) +### Equality operators (==, !=) -Like Equals methods, equality operators should return either `true` or `false`, and should not throw exceptions. +Like `Equals` methods, equality operators should return either `true` or `false`, and should not throw exceptions. -### Implicit Cast Operators +### Implicit cast operators Because the user is often unaware that an implicit cast operator has been called, an exception thrown by the implicit cast operator is unexpected. Therefore, no exceptions should be thrown from implicit cast operators. diff --git a/docs/fundamentals/code-analysis/quality-rules/ca2200.md b/docs/fundamentals/code-analysis/quality-rules/ca2200.md index 62aabab1d83f7..2973a54da3416 100644 --- a/docs/fundamentals/code-analysis/quality-rules/ca2200.md +++ b/docs/fundamentals/code-analysis/quality-rules/ca2200.md @@ -44,7 +44,7 @@ Do not suppress a warning from this rule. ## Example -The following example shows a method, `CatchAndRethrowExplicitly`, which violates the rule and a method, `CatchAndRethrowImplicitly`, which satisfies the rule. +The following example shows a method, `CatchAndRethrowExplicitly`, that violates the rule and a method, `CatchAndRethrowImplicitly`, that satisfies the rule. :::code language="csharp" source="snippets/csharp/all-rules/ca2200.cs" id="snippet1"::: diff --git a/docs/fundamentals/code-analysis/quality-rules/ca2208.md b/docs/fundamentals/code-analysis/quality-rules/ca2208.md index 515c25facf3e7..fb46bf9a85d1a 100644 --- a/docs/fundamentals/code-analysis/quality-rules/ca2208.md +++ b/docs/fundamentals/code-analysis/quality-rules/ca2208.md @@ -28,10 +28,8 @@ dev_langs: When a method has a parameter, and it throws an exception type that is, or derives from, , it is expected to call a constructor accepting a `paramName` parameter correctly. Possible causes include the following situations: -- A call is made to the default (parameterless) constructor of an exception type that is, or derives from, that has a constructor accepting a `paramName` parameter. - +- A call is made to the default (parameterless) constructor of an exception type that is, or derives from, that also has a constructor that accepts a `paramName` parameter. - An incorrect string argument is passed to a parameterized constructor of an exception type that is, or derives from, . - - One of the parameters' names is passed for the `message` argument of the constructor of exception type that is, or derives from, . ## Rule description diff --git a/docs/fundamentals/code-analysis/quality-rules/index.md b/docs/fundamentals/code-analysis/quality-rules/index.md index cd2f77f9568df..c3066b924a596 100644 --- a/docs/fundamentals/code-analysis/quality-rules/index.md +++ b/docs/fundamentals/code-analysis/quality-rules/index.md @@ -111,7 +111,7 @@ The following table lists code quality analysis rules. > | [CA1727: Use PascalCase for named placeholders](ca1727.md) | Use PascalCase for named placeholders in the logging message template. | > | [CA1801: Review unused parameters](ca1801.md) | A method signature includes a parameter that is not used in the method body. | > | [CA1802: Use Literals Where Appropriate](ca1802.md) | A field is declared static and read-only (Shared and ReadOnly in Visual Basic), and is initialized by using a value that is computable at compile time. Because the value that is assigned to the targeted field is computable at compile time, change the declaration to a const (Const in Visual Basic) field so that the value is computed at compile time instead of at run time. | -> | [CA1805: Do not initialize unnecessarily](ca1805.md) | The .NET runtime initializes all fields of reference types to their default values before running the constructor. In most cases, explicitly initializing a field to its default value is redundant, which adds to maintenance costs and may degrade performance (such as with increased assembly size). | +> | [CA1805: Do not initialize unnecessarily](ca1805.md) | The .NET runtime initializes all fields of reference types to their default values before running the constructor. In most cases, explicitly initializing a field to its default value is redundant, which adds to maintenance costs and might degrade performance (such as with increased assembly size). | > | [CA1806: Do not ignore method results](ca1806.md) | A new object is created but never used; or a method that creates and returns a new string is called and the new string is never used; or a COM or P/Invoke method returns an HRESULT or error code that is never used. | > | [CA1810: Initialize reference type static fields inline](ca1810.md) | When a type declares an explicit static constructor, the just-in-time (JIT) compiler adds a check to each static method and instance constructor of the type to make sure that the static constructor was previously called. Static constructor checks can decrease performance. | > | [CA1812: Avoid uninstantiated internal classes](ca1812.md) | An instance of an assembly-level type is not created by code in the assembly. | @@ -130,7 +130,7 @@ The following table lists code quality analysis rules. > | [CA1827: Do not use Count/LongCount when Any can be used](ca1827.md) | or method was used where method would be more efficient. | > | [CA1828: Do not use CountAsync/LongCountAsync when AnyAsync can be used](ca1828.md) | or method was used where method would be more efficient. | > | [CA1829: Use Length/Count property instead of Enumerable.Count method](ca1829.md) | LINQ method was used on a type that supports an equivalent, more efficient `Length` or `Count` property. | -> | [CA1830: Prefer strongly-typed Append and Insert method overloads on StringBuilder](ca1830.md) | and provide overloads for multiple types beyond . When possible, prefer the strongly-typed overloads over using ToString() and the string-based overload. | +> | [CA1830: Prefer strongly-typed Append and Insert method overloads on StringBuilder](ca1830.md) | and provide overloads for multiple types beyond . When possible, prefer the strongly-typed overloads over using ToString() and the string-based overload. | > | [CA1831: Use AsSpan instead of Range-based indexers for string when appropriate](ca1831.md) | When using a range-indexer on a string and implicitly assigning the value to ReadOnlySpan<char> type, the method will be used instead of , which produces a copy of requested portion of the string. | > | [CA1832: Use AsSpan or AsMemory instead of Range-based indexers for getting ReadOnlySpan or ReadOnlyMemory portion of an array](ca1832.md) | When using a range-indexer on an array and implicitly assigning the value to a or type, the method will be used instead of , which produces a copy of requested portion of the array. | > | [CA1833: Use AsSpan or AsMemory instead of Range-based indexers for getting Span or Memory portion of an array](ca1833.md) | When using a range-indexer on an array and implicitly assigning the value to a or type, the method will be used instead of , which produces a copy of requested portion of the array. | @@ -141,9 +141,9 @@ The following table lists code quality analysis rules. > | [CA1838: Avoid `StringBuilder` parameters for P/Invokes](ca1838.md) | Marshalling of 'StringBuilder' always creates a native buffer copy, resulting in multiple allocations for one marshalling operation. | > | [CA1839: Use Environment.ProcessPath instead of Process.GetCurrentProcess().MainModule.FileName](ca1839.md) | `Environment.ProcessPath` is simpler and faster than `Process.GetCurrentProcess().MainModule.FileName`. | > | [CA1840: Use Environment.CurrentManagedThreadId instead of Thread.CurrentThread.ManagedThreadId](ca1840.md) | `Environment.CurrentManagedThreadId` is more compact and efficient than `Thread.CurrentThread.ManagedThreadId`. | -> | [CA1841: Prefer Dictionary Contains methods](ca1841.md) | Calling `Contains` on the `Keys` or `Values` collection may often be more expensive than calling `ContainsKey` or `ContainsValue` on the dictionary itself. | -> | [CA1842: Do not use 'WhenAll' with a single task](ca1842.md) | Using `WhenAll` with a single task may result in performance loss. Await or return the task instead. | -> | [CA1843: Do not use 'WaitAll' with a single task](ca1843.md) | Using `WaitAll` with a single task may result in performance loss. Await or return the task instead. | +> | [CA1841: Prefer Dictionary Contains methods](ca1841.md) | Calling `Contains` on the `Keys` or `Values` collection might often be more expensive than calling `ContainsKey` or `ContainsValue` on the dictionary itself. | +> | [CA1842: Do not use 'WhenAll' with a single task](ca1842.md) | Using `WhenAll` with a single task might result in performance loss. Await or return the task instead. | +> | [CA1843: Do not use 'WaitAll' with a single task](ca1843.md) | Using `WaitAll` with a single task might result in performance loss. Await or return the task instead. | > | [CA1844: Provide memory-based overrides of async methods when subclassing 'Stream'](ca1844.md) | To improve performance, override the memory-based async methods when subclassing 'Stream'. Then implement the array-based methods in terms of the memory-based methods. | > | [CA1845: Use span-based 'string.Concat'](ca1845.md) | It is more efficient to use `AsSpan` and `string.Concat`, instead of `Substring` and a concatenation operator. | > | [CA1846: Prefer `AsSpan` over `Substring`](ca1846.md) | `AsSpan` is more efficient than `Substring`. `Substring` performs an O(n) string copy, while `AsSpan` does not and has a constant cost. `AsSpan` also does not perform any heap allocations. | @@ -177,10 +177,10 @@ The following table lists code quality analysis rules. > | [CA2008: Do not create tasks without passing a TaskScheduler](ca2008.md) | A task creation or continuation operation uses a method overload that does not specify a parameter. | > | [CA2009: Do not call ToImmutableCollection on an ImmutableCollection value](ca2009.md) | `ToImmutable` method was unnecessarily called on an immutable collection from namespace. | > | [CA2011: Do not assign property within its setter](ca2011.md) | A property was accidentally assigned a value within its own [set accessor](../../../csharp/programming-guide/classes-and-structs/using-properties.md#the-set-accessor). | -> | [CA2012: Use ValueTasks correctly](ca2012.md) | ValueTasks returned from member invocations are intended to be directly awaited. Attempts to consume a ValueTask multiple times or to directly access one's result before it's known to be completed may result in an exception or corruption. Ignoring such a ValueTask is likely an indication of a functional bug and may degrade performance. | +> | [CA2012: Use ValueTasks correctly](ca2012.md) | ValueTasks returned from member invocations are intended to be directly awaited. Attempts to consume a ValueTask multiple times or to directly access one's result before it's known to be completed might result in an exception or corruption. Ignoring such a ValueTask is likely an indication of a functional bug and might degrade performance. | > | [CA2013: Do not use ReferenceEquals with value types](ca2013.md) | When comparing values using , if objA and objB are value types, they are boxed before they are passed to the method. This means that even if both objA and objB represent the same instance of a value type, the method nevertheless returns false. | -> | [CA2014: Do not use stackalloc in loops.](ca2014.md) | Stack space allocated by a stackalloc is only released at the end of the current method's invocation. Using it in a loop can result in unbounded stack growth and eventual stack overflow conditions. | -> | [CA2015: Do not define finalizers for types derived from MemoryManager<T>](ca2015.md) | Adding a finalizer to a type derived from may permit memory to be freed while it is still in use by a . | +> | [CA2014: Do not use stackalloc in loops.](ca2014.md) | Stack space allocated by a stackalloc is only released at the end of the current method's invocation. Using it in a loop can result in unbounded stack growth and eventual stack overflow conditions. | +> | [CA2015: Do not define finalizers for types derived from MemoryManager<T>](ca2015.md) | Adding a finalizer to a type derived from might permit memory to be freed while it is still in use by a . | > | [CA2016: Forward the CancellationToken parameter to methods that take one](ca2016.md) | Forward the `CancellationToken` parameter to methods that take one to ensure the operation cancellation notifications gets properly propagated, or pass in `CancellationToken.None` explicitly to indicate intentionally not propagating the token. | > | [CA2017: Parameter count mismatch](ca2017.md) | Number of parameters supplied in the logging message template do not match the number of named placeholders. | > | [CA2018: The `count` argument to `Buffer.BlockCopy` should specify the number of bytes to copy](ca2018.md) | When using `Buffer.BlockCopy`, the `count` argument specifies the number of bytes to copy. You should only use `Array.Length` for the `count` argument on arrays whose elements are exactly one byte in size. `byte`, `sbyte`, and `bool` arrays have elements that are one byte in size. | @@ -195,10 +195,10 @@ The following table lists code quality analysis rules. > | [CA2200: Rethrow to preserve stack details](ca2200.md) | An exception is rethrown and the exception is explicitly specified in the throw statement. If an exception is rethrown by specifying the exception in the throw statement, the list of method calls between the original method that threw the exception and the current method is lost. | > | [CA2201: Do not raise reserved exception types](ca2201.md) | This makes the original error difficult to detect and debug. | > | [CA2207: Initialize value type static fields inline](ca2207.md) | A value type declares an explicit static constructor. To fix a violation of this rule, initialize all static data when it is declared and remove the static constructor. | -> | [CA2208: Instantiate argument exceptions correctly](ca2208.md) | A call is made to the default (parameterless) constructor of an exception type that is or derives from ArgumentException, or an incorrect string argument is passed to a parameterized constructor of an exception type that is or derives from ArgumentException. | +> | [CA2208: Instantiate argument exceptions correctly](ca2208.md) | A call is made to the default (parameterless) constructor of an exception type that is or derives from `ArgumentException`, or an incorrect string argument is passed to a parameterized constructor of an exception type that is or derives from `ArgumentException`. | > | [CA2211: Non-constant fields should not be visible](ca2211.md) | Static fields that are neither constants nor read-only are not thread-safe. Access to such a field must be carefully controlled and requires advanced programming techniques to synchronize access to the class object. | > | [CA2213: Disposable fields should be disposed](ca2213.md) | A type that implements System.IDisposable declares fields that are of types that also implement IDisposable. The Dispose method of the field is not called by the Dispose method of the declaring type. | -> | [CA2214: Do not call overridable methods in constructors](ca2214.md) | When a constructor calls a virtual method, the constructor for the instance that invokes the method may not have executed. | +> | [CA2214: Do not call overridable methods in constructors](ca2214.md) | When a constructor calls a virtual method, the constructor for the instance that invokes the method might not have executed. | > | [CA2215: Dispose methods should call base class dispose](ca2215.md) | If a type inherits from a disposable type, it must call the Dispose method of the base type from its own Dispose method. | > | [CA2216: Disposable types should declare finalizer](ca2216.md) | A type that implements System.IDisposable and has fields that suggest the use of unmanaged resources does not implement a finalizer, as described by Object.Finalize. | > | [CA2217: Do not mark enums with FlagsAttribute](ca2217.md) | An externally visible enumeration is marked by using FlagsAttribute, and it has one or more values that are not powers of two or a combination of the other defined values on the enumeration. | @@ -219,7 +219,7 @@ The following table lists code quality analysis rules. > | [CA2244: Do not duplicate indexed element initializations](ca2244.md) | An object initializer has more than one indexed element initializer with the same constant index. All but the last initializer are redundant. | > | [CA2245: Do not assign a property to itself](ca2245.md) | A property was accidentally assigned to itself. | > | [CA2246: Do not assign a symbol and its member in the same statement](ca2246.md) | Assigning a symbol and its member, that is, a field or a property, in the same statement is not recommended. It is not clear if the member access was intended to use the symbol's old value prior to the assignment or the new value from the assignment in this statement. | -> | [CA2247: Argument passed to TaskCompletionSource constructor should be TaskCreationOptions enum instead of TaskContinuationOptions enum.](ca2247.md) | TaskCompletionSource has constructors that take TaskCreationOptions that control the underlying Task, and constructors that take object state that's stored in the task. Accidentally passing a TaskContinuationOptions instead of a TaskCreationOptions will result in the call treating the options as state. | +> | [CA2247: Argument passed to TaskCompletionSource constructor should be TaskCreationOptions enum instead of TaskContinuationOptions enum.](ca2247.md) | TaskCompletionSource has constructors that take TaskCreationOptions that control the underlying Task, and constructors that take object state that's stored in the task. Accidentally passing a TaskContinuationOptions instead of a TaskCreationOptions will result in the call treating the options as state. | > | [CA2248: Provide correct enum argument to Enum.HasFlag](ca2248.md) | The enum type passed as an argument to the `HasFlag` method call is different from the calling enum type. | > | [CA2249: Consider using String.Contains instead of String.IndexOf](ca2249.md) | Calls to `string.IndexOf` where the result is used to check for the presence/absence of a substring can be replaced by `string.Contains`. | > | [CA2250: Use `ThrowIfCancellationRequested`](ca2250.md) | `ThrowIfCancellationRequested` automatically checks whether the token has been canceled, and throws an `OperationCanceledException` if it has. | @@ -229,7 +229,7 @@ The following table lists code quality analysis rules. > | [CA2254: Template should be a static expression](ca2254.md) | The logging message template should not vary between calls. | > | [CA2255: The `ModuleInitializer` attribute should not be used in libraries](ca2255.md) | Module initializers are intended to be used by application code to ensure an application's components are initialized before the application code begins executing. | > | [CA2256: All members declared in parent interfaces must have an implementation in a DynamicInterfaceCastableImplementation-attributed interface](ca2256.md) | Types attributed with `DynamicInterfaceCastableImplementationAttribute` act as an interface implementation for a type that implements the `IDynamicInterfaceCastable` type. As a result, it must provide an implementation of all of the members defined in the inherited interfaces, because the type that implements `IDynamicInterfaceCastable` will not provide them otherwise. | -> | [CA2257: Members defined on an interface with 'DynamicInterfaceCastableImplementationAttribute' should be 'static'](ca2257.md) | Since a type that implements `IDynamicInterfaceCastable` may not implement a dynamic interface in metadata, calls to an instance interface member that is not an explicit implementation defined on this type are likely to fail at run time. Mark new interface members `static` to avoid run-time errors. | +> | [CA2257: Members defined on an interface with 'DynamicInterfaceCastableImplementationAttribute' should be 'static'](ca2257.md) | Since a type that implements `IDynamicInterfaceCastable` might not implement a dynamic interface in metadata, calls to an instance interface member that is not an explicit implementation defined on this type are likely to fail at run time. Mark new interface members `static` to avoid run-time errors. | > | [CA2258: Providing a 'DynamicInterfaceCastableImplementation' interface in Visual Basic is unsupported](ca2258.md) | Providing a functional `DynamicInterfaceCastableImplementationAttribute`-attributed interface requires the Default Interface Members feature, which is unsupported in Visual Basic. | > | [CA2259: Ensure `ThreadStatic` is only used with static fields](ca2259.md) | only affects `static` (`Shared` in Visual Basic) fields. When applied to instance fields, the attribute has no impact on behavior. | > | [CA2260: Implement generic math interfaces correctly](ca2260.md) | Generic math interfaces require the derived type itself to be used for the self-recurring type parameter. | @@ -252,14 +252,14 @@ The following table lists code quality analysis rules. > | [CA2328: Ensure that JsonSerializerSettings are secure](ca2328.md) | Insecure deserializers are vulnerable when deserializing untrusted data. An attacker could modify the serialized data to include unexpected types to inject objects with malicious side effects. | > | [CA2329: Do not deserialize with JsonSerializer using an insecure configuration](ca2329.md) | Insecure deserializers are vulnerable when deserializing untrusted data. An attacker could modify the serialized data to include unexpected types to inject objects with malicious side effects. | > | [CA2330: Ensure that JsonSerializer has a secure configuration when deserializing](ca2330.md) | Insecure deserializers are vulnerable when deserializing untrusted data. An attacker could modify the serialized data to include unexpected types to inject objects with malicious side effects. | -> | [CA2350: Ensure DataTable.ReadXml()'s input is trusted](ca2350.md) | When deserializing a with untrusted input, an attacker can craft malicious input to perform a denial of service attack. There may be unknown remote code execution vulnerabilities. | -> | [CA2351: Ensure DataSet.ReadXml()'s input is trusted](ca2351.md) | When deserializing a with untrusted input, an attacker can craft malicious input to perform a denial of service attack. There may be unknown remote code execution vulnerabilities. | +> | [CA2350: Ensure DataTable.ReadXml()'s input is trusted](ca2350.md) | When deserializing a with untrusted input, an attacker can craft malicious input to perform a denial of service attack. There might be unknown remote code execution vulnerabilities. | +> | [CA2351: Ensure DataSet.ReadXml()'s input is trusted](ca2351.md) | When deserializing a with untrusted input, an attacker can craft malicious input to perform a denial of service attack. There might be unknown remote code execution vulnerabilities. | > | [CA2352: Unsafe DataSet or DataTable in serializable type can be vulnerable to remote code execution attacks](ca2352.md) | A class or struct marked with contains a or field or property, and doesn't have a . | > | [CA2353: Unsafe DataSet or DataTable in serializable type](ca2353.md) | A class or struct marked with an XML serialization attribute or a data contract attribute contains a or field or property. | > | [CA2354: Unsafe DataSet or DataTable in deserialized object graph can be vulnerable to remote code execution attack](ca2354.md) | Deserializing with an serialized, and the casted type's object graph can include a or . | > | [CA2355: Unsafe DataSet or DataTable in deserialized object graph](ca2355.md) | Deserializing when the casted or specified type's object graph can include a or . | -> | [CA2356: Unsafe DataSet or DataTable in web deserialized object graph](ca2356.md) | A method with a or has a parameter that may reference a or . | -> | [CA2361: Ensure autogenerated class containing DataSet.ReadXml() is not used with untrusted data](ca2361.md) | When deserializing a with untrusted input, an attacker can craft malicious input to perform a denial of service attack. There may be unknown remote code execution vulnerabilities. | +> | [CA2356: Unsafe DataSet or DataTable in web deserialized object graph](ca2356.md) | A method with a or has a parameter that might reference a or . | +> | [CA2361: Ensure autogenerated class containing DataSet.ReadXml() is not used with untrusted data](ca2361.md) | When deserializing a with untrusted input, an attacker can craft malicious input to perform a denial of service attack. There might be unknown remote code execution vulnerabilities. | > | [CA2362: Unsafe DataSet or DataTable in autogenerated serializable type can be vulnerable to remote code execution attacks](ca2362.md) | When deserializing untrusted input with and the deserialized object graph contains a or , an attacker can craft a malicious payload to perform a remote code execution attack. | > | [CA3001: Review code for SQL injection vulnerabilities](ca3001.md) | When working with untrusted input and SQL commands, be mindful of SQL injection attacks. An SQL injection attack can execute malicious SQL commands, compromising the security and integrity of your application. | > | [CA3002: Review code for XSS vulnerabilities](ca3002.md) | When working with untrusted input from web requests, be mindful of cross-site scripting (XSS) attacks. An XSS attack injects untrusted input into raw HTML output, allowing the attacker to execute malicious scripts or maliciously modify content in your web page. | @@ -268,15 +268,15 @@ The following table lists code quality analysis rules. > | [CA3005: Review code for LDAP injection vulnerabilities](ca3005.md) | When working with untrusted input, be mindful of Lightweight Directory Access Protocol (LDAP) injection attacks. An attacker can potentially run malicious LDAP statements against information directories. Applications that use user input to construct dynamic LDAP statements to access directory services are particularly vulnerable. | > | [CA3006: Review code for process command injection vulnerabilities](ca3006.md) | When working with untrusted input, be mindful of command injection attacks. A command injection attack can execute malicious commands on the underlying operating system, compromising the security and integrity of your server. | > | [CA3007: Review code for open redirect vulnerabilities](ca3007.md) | When working with untrusted input, be mindful of open redirect vulnerabilities. An attacker can exploit an open redirect vulnerability to use your website to give the appearance of a legitimate URL, but redirect an unsuspecting visitor to a phishing or other malicious webpage. | -> | [CA3008: Review code for XPath injection vulnerabilities](ca3008.md) | When working with untrusted input, be mindful of XPath injection attacks. Constructing XPath queries using untrusted input may allow an attacker to maliciously manipulate the query to return an unintended result, and possibly disclose the contents of the queried XML. | +> | [CA3008: Review code for XPath injection vulnerabilities](ca3008.md) | When working with untrusted input, be mindful of XPath injection attacks. Constructing XPath queries using untrusted input might allow an attacker to maliciously manipulate the query to return an unintended result, and possibly disclose the contents of the queried XML. | > | [CA3009: Review code for XML injection vulnerabilities](ca3009.md) | When working with untrusted input, be mindful of XML injection attacks. | > | [CA3010: Review code for XAML injection vulnerabilities](ca3010.md) | When working with untrusted input, be mindful of XAML injection attacks. XAML is a markup language that directly represents object instantiation and execution. That means elements created in XAML can interact with system resources (for example, network access and file system IO). | -> | [CA3011: Review code for DLL injection vulnerabilities](ca3011.md) | When working with untrusted input, be mindful of loading untrusted code. If your web application loads untrusted code, an attacker may be able to inject malicious DLLs into your process and execute malicious code. | +> | [CA3011: Review code for DLL injection vulnerabilities](ca3011.md) | When working with untrusted input, be mindful of loading untrusted code. If your web application loads untrusted code, an attacker might be able to inject malicious DLLs into your process and execute malicious code. | > | [CA3012: Review code for regex injection vulnerabilities](ca3012.md) | When working with untrusted input, be mindful of regex injection attacks. An attacker can use regex injection to maliciously modify a regular expression, to make the regex match unintended results, or to make the regex consume excessive CPU resulting in a Denial of Service attack. | -> | [CA3061: Do not add schema by URL](ca3061.md) | Do not use the unsafe overload of the Add method because it may cause dangerous external references. | -> | [CA3075: Insecure DTD Processing](ca3075.md) | If you use insecure DTDProcessing instances or reference external entity sources, the parser may accept untrusted input and disclose sensitive information to attackers. | -> | [CA3076: Insecure XSLT Script Execution](ca3076.md) | If you execute Extensible Stylesheet Language Transformations (XSLT) in .NET applications insecurely, the processor may resolve untrusted URI references that could disclose sensitive information to attackers, leading to Denial of Service and Cross-Site attacks. | -> | [CA3077: Insecure Processing in API Design, XML Document and XML Text Reader](ca3077.md) | When designing an API derived from XMLDocument and XMLTextReader, be mindful of DtdProcessing. Using insecure DTDProcessing instances when referencing or resolving external entity sources or setting insecure values in the XML may lead to information disclosure. | +> | [CA3061: Do not add schema by URL](ca3061.md) | Do not use the unsafe overload of the Add method because it might cause dangerous external references. | +> | [CA3075: Insecure DTD Processing](ca3075.md) | If you use insecure DTDProcessing instances or reference external entity sources, the parser might accept untrusted input and disclose sensitive information to attackers. | +> | [CA3076: Insecure XSLT Script Execution](ca3076.md) | If you execute Extensible Stylesheet Language Transformations (XSLT) in .NET applications insecurely, the processor might resolve untrusted URI references that could disclose sensitive information to attackers, leading to Denial of Service and Cross-Site attacks. | +> | [CA3077: Insecure Processing in API Design, XML Document and XML Text Reader](ca3077.md) | When designing an API derived from XMLDocument and XMLTextReader, be mindful of DtdProcessing. Using insecure DTDProcessing instances when referencing or resolving external entity sources or setting insecure values in the XML might lead to information disclosure. | > | [CA3147: Mark verb handlers with ValidateAntiForgeryToken](ca3147.md) | When designing an ASP.NET MVC controller, be mindful of cross-site request forgery attacks. A cross-site request forgery attack can send malicious requests from an authenticated user to your ASP.NET MVC controller. | > | [CA5350: Do Not Use Weak Cryptographic Algorithms](ca5350.md) | Weak encryption algorithms and hashing functions are used today for a number of reasons, but they should not be used to guarantee the confidentiality or integrity of the data they protect. This rule triggers when it finds TripleDES, SHA1, or RIPEMD160 algorithms in the code.| > | [CA5351: Do Not Use Broken Cryptographic Algorithms](ca5351.md) | Broken cryptographic algorithms are not considered secure and their use should be strongly discouraged. This rule triggers when it finds the MD5 hash algorithm or either the DES or RC2 encryption algorithms in code. | @@ -288,13 +288,13 @@ The following table lists code quality analysis rules. > | [CA5363: Do not disable request validation](ca5363.md) | Request validation is a feature in ASP.NET that examines HTTP requests and determines whether they contain potentially dangerous content that can lead to injection attacks, including cross-site-scripting. | > | [CA5364: Do not use deprecated security protocols](ca5364.md) | Transport Layer Security (TLS) secures communication between computers, most commonly with Hypertext Transfer Protocol Secure (HTTPS). Older protocol versions of TLS are less secure than TLS 1.2 and TLS 1.3 and are more likely to have new vulnerabilities. Avoid older protocol versions to minimize risk. | > | [CA5365: Do Not Disable HTTP Header Checking](ca5365.md) | HTTP header checking enables encoding of the carriage return and newline characters, \r and \n, that are found in response headers. This encoding can help to avoid injection attacks that exploit an application that echoes untrusted data contained by the header. | -> | [CA5366: Use XmlReader For DataSet Read XML](ca5366.md) | Using a to read XML with untrusted data may load dangerous external references, which should be restricted by using an with a secure resolver or with DTD processing disabled. | +> | [CA5366: Use XmlReader For DataSet Read XML](ca5366.md) | Using a to read XML with untrusted data might load dangerous external references, which should be restricted by using an with a secure resolver or with DTD processing disabled. | > | [CA5367: Do Not Serialize Types With Pointer Fields](ca5367.md) | This rule checks whether there's a serializable class with a pointer field or property. Members that can't be serialized can be a pointer, such as static members or fields marked with . | > | [CA5368: Set ViewStateUserKey For Classes Derived From Page](ca5368.md) | Setting the property can help you prevent attacks on your application by allowing you to assign an identifier to the view-state variable for individual users so that attackers cannot use the variable to generate an attack. Otherwise, there will be vulnerabilities to cross-site request forgery. | -> | [CA5369: Use XmlReader for Deserialize](ca5369.md) | Processing untrusted DTD and XML schemas may enable loading dangerous external references, which should be restricted by using an XmlReader with a secure resolver or with DTD and XML inline schema processing disabled. | -> | [CA5370: Use XmlReader for validating reader](ca5370.md) | Processing untrusted DTD and XML schemas may enable loading dangerous external references. This dangerous loading can be restricted by using an XmlReader with a secure resolver or with DTD and XML inline schema processing disabled. | -> | [CA5371: Use XmlReader for schema read](ca5371.md) | Processing untrusted DTD and XML schemas may enable loading dangerous external references. Using an XmlReader with a secure resolver or with DTD and XML inline schema processing disabled restricts this. | -> | [CA5372: Use XmlReader for XPathDocument](ca5372.md) | Processing XML from untrusted data may load dangerous external references, which can be restricted by using an XmlReader with a secure resolver or with DTD processing disabled. | +> | [CA5369: Use XmlReader for Deserialize](ca5369.md) | Processing untrusted DTD and XML schemas might enable loading dangerous external references, which should be restricted by using an XmlReader with a secure resolver or with DTD and XML inline schema processing disabled. | +> | [CA5370: Use XmlReader for validating reader](ca5370.md) | Processing untrusted DTD and XML schemas might enable loading dangerous external references. This dangerous loading can be restricted by using an XmlReader with a secure resolver or with DTD and XML inline schema processing disabled. | +> | [CA5371: Use XmlReader for schema read](ca5371.md) | Processing untrusted DTD and XML schemas might enable loading dangerous external references. Using an XmlReader with a secure resolver or with DTD and XML inline schema processing disabled restricts this. | +> | [CA5372: Use XmlReader for XPathDocument](ca5372.md) | Processing XML from untrusted data might load dangerous external references, which can be restricted by using an XmlReader with a secure resolver or with DTD processing disabled. | > | [CA5373: Do not use obsolete key derivation function](ca5373.md) | This rule detects the invocation of weak key derivation methods and `Rfc2898DeriveBytes.CryptDeriveKey`. used a weak algorithm PBKDF1. | > | [CA5374: Do Not Use XslTransform](ca5374.md) | This rule checks if is instantiated in the code. is now obsolete and shouldn't be used. | > | [CA5375: Do not use account shared access signature](ca5375.md) | An account SAS can delegate access to read, write, and delete operations on blob containers, tables, queues, and file shares that are not permitted with a service SAS. However, it doesn't support container-level policies and has less flexibility and control over the permissions that are granted. Once malicious users get it, your storage account will be compromised easily. | @@ -308,19 +308,19 @@ The following table lists code quality analysis rules. > | [CA5383: Ensure use secure cookies in ASP.NET Core](ca5383.md) | Applications available over HTTPS must use secure cookies, which indicate to the browser that the cookie should only be transmitted using Secure Sockets Layer (SSL). | > | [CA5384: Do not use digital signature algorithm (DSA)](ca5384.md) | DSA is a weak asymmetric encryption algorithm. | > | [CA5385: Use Rivest–Shamir–Adleman (RSA) algorithm with sufficient key size](ca5385.md) | An RSA key smaller than 2048 bits is more vulnerable to brute force attacks. | -> | [CA5386: Avoid hardcoding SecurityProtocolType value](ca5386.md) | Transport Layer Security (TLS) secures communication between computers, most commonly with Hypertext Transfer Protocol Secure (HTTPS). Protocol versions TLS 1.0 and TLS 1.1 are deprecated, while TLS 1.2 and TLS 1.3 are current. In the future, TLS 1.2 and TLS 1.3 may be deprecated. To ensure that your application remains secure, avoid hardcoding a protocol version and target at least .NET Framework v4.7.1. | +> | [CA5386: Avoid hardcoding SecurityProtocolType value](ca5386.md) | Transport Layer Security (TLS) secures communication between computers, most commonly with Hypertext Transfer Protocol Secure (HTTPS). Protocol versions TLS 1.0 and TLS 1.1 are deprecated, while TLS 1.2 and TLS 1.3 are current. In the future, TLS 1.2 and TLS 1.3 might be deprecated. To ensure that your application remains secure, avoid hardcoding a protocol version and target at least .NET Framework v4.7.1. | > | [CA5387: Do not use weak key derivation function with insufficient iteration count](ca5387.md) | This rule checks if a cryptographic key was generated by with an iteration count of less than 100,000. A higher iteration count can help mitigate against dictionary attacks that try to guess the generated cryptographic key. | -> | [CA5388: Ensure sufficient iteration count when using weak key derivation function](ca5388.md) | This rule checks if a cryptographic key was generated by with an iteration count that may be less than 100,000. A higher iteration count can help mitigate against dictionary attacks that try to guess the generated cryptographic key. | +> | [CA5388: Ensure sufficient iteration count when using weak key derivation function](ca5388.md) | This rule checks if a cryptographic key was generated by with an iteration count that might be less than 100,000. A higher iteration count can help mitigate against dictionary attacks that try to guess the generated cryptographic key. | > | [CA5389: Do not add archive item's path to the target file system path](ca5389.md) | File path can be relative and can lead to file system access outside of the expected file system target path, leading to malicious config changes and remote code execution via lay-and-wait technique. | > | [CA5390: Do not hard-code encryption key](ca5390.md) | For a symmetric algorithm to be successful, the secret key must be known only to the sender and the receiver. When a key is hard-coded, it is easily discovered. Even with compiled binaries, it is easy for malicious users to extract it. Once the private key is compromised, the cipher text can be decrypted directly and is not protected anymore. | -> | [CA5391: Use antiforgery tokens in ASP.NET Core MVC controllers](ca5391.md) | Handling a `POST`, `PUT`, `PATCH`, or `DELETE` request without validating an antiforgery token may be vulnerable to cross-site request forgery attacks. A cross-site request forgery attack can send malicious requests from an authenticated user to your ASP.NET Core MVC controller. | +> | [CA5391: Use antiforgery tokens in ASP.NET Core MVC controllers](ca5391.md) | Handling a `POST`, `PUT`, `PATCH`, or `DELETE` request without validating an antiforgery token might be vulnerable to cross-site request forgery attacks. A cross-site request forgery attack can send malicious requests from an authenticated user to your ASP.NET Core MVC controller. | > | [CA5392: Use DefaultDllImportSearchPaths attribute for P/Invokes](ca5392.md) | By default, P/Invoke functions using probe a number of directories, including the current working directory for the library to load. This can be a security issue for certain applications, leading to DLL hijacking. | > | [CA5393: Do not use unsafe DllImportSearchPath value](ca5393.md) | There could be a malicious DLL in the default DLL search directories and assembly directories. Or, depending on where your application is run from, there could be a malicious DLL in the application's directory. | -> | [CA5394: Do not use insecure randomness](ca5394.md) | Using a cryptographically weak pseudo-random number generator may allow an attacker to predict what security-sensitive value will be generated. | +> | [CA5394: Do not use insecure randomness](ca5394.md) | Using a cryptographically weak pseudo-random number generator might allow an attacker to predict what security-sensitive value will be generated. | > | [CA5395: Miss HttpVerb attribute for action methods](ca5395.md) | All the action methods that create, edit, delete, or otherwise modify data needs to be protected with the antiforgery attribute from cross-site request forgery attacks. Performing a GET operation should be a safe operation that has no side effects and doesn't modify your persisted data. | > | [CA5396: Set HttpOnly to true for HttpCookie](ca5396.md) | As a defense in depth measure, ensure security sensitive HTTP cookies are marked as HttpOnly. This indicates web browsers should disallow scripts from accessing the cookies. Injected malicious scripts are a common way of stealing cookies. | > | [CA5397: Do not use deprecated SslProtocols values](ca5397.md) | Transport Layer Security (TLS) secures communication between computers, most commonly with Hypertext Transfer Protocol Secure (HTTPS). Older protocol versions of TLS are less secure than TLS 1.2 and TLS 1.3 and are more likely to have new vulnerabilities. Avoid older protocol versions to minimize risk. | -> | [CA5398: Avoid hardcoded SslProtocols values](ca5398.md) | Transport Layer Security (TLS) secures communication between computers, most commonly with Hypertext Transfer Protocol Secure (HTTPS). Protocol versions TLS 1.0 and TLS 1.1 are deprecated, while TLS 1.2 and TLS 1.3 are current. In the future, TLS 1.2 and TLS 1.3 may be deprecated. To ensure that your application remains secure, avoid hardcoding a protocol version. | +> | [CA5398: Avoid hardcoded SslProtocols values](ca5398.md) | Transport Layer Security (TLS) secures communication between computers, most commonly with Hypertext Transfer Protocol Secure (HTTPS). Protocol versions TLS 1.0 and TLS 1.1 are deprecated, while TLS 1.2 and TLS 1.3 are current. In the future, TLS 1.2 and TLS 1.3 might be deprecated. To ensure that your application remains secure, avoid hardcoding a protocol version. | > | [CA5399: Definitely disable HttpClient certificate revocation list check](ca5399.md) | A revoked certificate isn't trusted anymore. It could be used by attackers passing some malicious data or stealing sensitive data in HTTPS communication. | > | [CA5400: Ensure HttpClient certificate revocation list check is not disabled](ca5400.md) | A revoked certificate isn't trusted anymore. It could be used by attackers passing some malicious data or stealing sensitive data in HTTPS communication. | > | [CA5401: Do not use CreateEncryptor with non-default IV](ca5401.md) | Symmetric encryption should always use a non-repeatable initialization vector to prevent dictionary attacks. | diff --git a/docs/fundamentals/code-analysis/quality-rules/snippets/csharp/all-rules/ca2200.cs b/docs/fundamentals/code-analysis/quality-rules/snippets/csharp/all-rules/ca2200.cs index 791b5bb577d12..0330140d2d67f 100644 --- a/docs/fundamentals/code-analysis/quality-rules/snippets/csharp/all-rules/ca2200.cs +++ b/docs/fundamentals/code-analysis/quality-rules/snippets/csharp/all-rules/ca2200.cs @@ -19,8 +19,7 @@ void CatchException() } catch (ArithmeticException e) { - Console.WriteLine("Explicitly specified:{0}{1}", - Environment.NewLine, e.StackTrace); + Console.WriteLine($"Explicitly specified:{Environment.NewLine}{e.StackTrace}"); } try @@ -29,8 +28,7 @@ void CatchException() } catch (ArithmeticException e) { - Console.WriteLine("{0}Implicitly specified:{0}{1}", - Environment.NewLine, e.StackTrace); + Console.WriteLine($"{Environment.NewLine}Implicitly specified:{Environment.NewLine}{e.StackTrace}"); } } diff --git a/docs/standard/exceptions/best-practices-for-exceptions.md b/docs/standard/exceptions/best-practices-for-exceptions.md index 6420b6d9d3cda..ae4267d5215d7 100644 --- a/docs/standard/exceptions/best-practices-for-exceptions.md +++ b/docs/standard/exceptions/best-practices-for-exceptions.md @@ -1,129 +1,74 @@ --- -title: "Best Practices for exceptions - .NET" +title: "Best practices for exceptions" description: Learn best practices for exceptions, such as using try/catch/finally, handling common conditions without exceptions, and using predefined .NET exception types. -ms.date: 02/15/2023 -ms.custom: devdivchpfy22 +ms.date: 04/30/2024 dev_langs: - "csharp" - "vb" - - "cpp" helpviewer_keywords: - "exceptions, best practices" --- # Best practices for exceptions -A well-designed app handles exceptions and errors to prevent app crashes. This article describes best practices for handling and creating exceptions. +Proper exception handling is essential for application reliability. You can intentionally handle expected exceptions to prevent your app from crashing. However, a crashed app is more reliable and diagnosable than an app with undefined behavior. -## Use try/catch/finally blocks to recover from errors or release resources +This article describes best practices for handling and creating exceptions. -Use `try`/`catch` blocks around code that can potentially generate an exception, and your code can recover from that exception. In `catch` blocks, always order exceptions from the most derived to the least derived. All exceptions derive from the class. More derived exceptions aren't handled by a catch clause that's preceded by a catch clause for a base exception class. When your code can't recover from an exception, don't catch that exception. Enable methods further up the call stack to recover if possible. +## Handling exceptions + +The following best practices concern how you handle exceptions: + +- [Use try/catch/finally blocks to recover from errors or release resources](#use-trycatchfinally-blocks-to-recover-from-errors-or-release-resources) +- [Handle common conditions to avoid exceptions](#handle-common-conditions-to-avoid-exceptions) +- [Catch cancellation and asynchronous exceptions](#catch-cancellation-and-asynchronous-exceptions) +- [Design classes so that exceptions can be avoided](#design-classes-so-that-exceptions-can-be-avoided) +- [Restore state when methods don't complete due to exceptions](#restore-state-when-methods-dont-complete-due-to-exceptions) +- [Capture exceptions to rethrow later](#capture-exceptions-to-rethrow-later) + +### Use try/catch/finally blocks to recover from errors or release resources + +For code that can potentially generate an exception, and when your app can recover from that exception, use `try`/`catch` blocks around the code. In `catch` blocks, always order exceptions from the most derived to the least derived. (All exceptions derive from the class. More derived exceptions aren't handled by a `catch` clause that's preceded by a `catch` clause for a base exception class.) When your code can't recover from an exception, don't catch that exception. Enable methods further up the call stack to recover if possible. Clean up resources that are allocated with either `using` statements or `finally` blocks. Prefer `using` statements to automatically clean up resources when exceptions are thrown. Use `finally` blocks to clean up resources that don't implement . Code in a `finally` clause is almost always executed even when exceptions are thrown. -## Handle common conditions without throwing exceptions +### Handle common conditions to avoid exceptions -For conditions that are likely to occur but might trigger an exception, consider handling them in a way that will avoid the exception. For example, if you try to close a connection that's already closed, you'll get an `InvalidOperationException`. You can avoid that by using an `if` statement to check the connection state before trying to close it. +For conditions that are likely to occur but might trigger an exception, consider handling them in a way that avoids the exception. For example, if you try to close a connection that's already closed, you'll get an `InvalidOperationException`. You can avoid that by using an `if` statement to check the connection state before trying to close it. -[!code-cpp[Conceptual.Exception.Handling#2](~/samples/snippets/cpp/VS_Snippets_CLR/conceptual.exception.handling/cpp/source.cpp#2)] -[!code-csharp[Conceptual.Exception.Handling#2](~/samples/snippets/csharp/VS_Snippets_CLR/conceptual.exception.handling/cs/source.cs#2)] +[!code-csharp[Conceptual.Exception.Handling#2](./snippets/best-practices/csharp/source.cs#2)] [!code-vb[Conceptual.Exception.Handling#2](~/samples/snippets/visualbasic/VS_Snippets_CLR/conceptual.exception.handling/vb/source.vb#2)] If you don't check the connection state before closing, you can catch the `InvalidOperationException` exception. -[!code-cpp[Conceptual.Exception.Handling#3](~/samples/snippets/cpp/VS_Snippets_CLR/conceptual.exception.handling/cpp/source.cpp#3)] -[!code-csharp[Conceptual.Exception.Handling#3](~/samples/snippets/csharp/VS_Snippets_CLR/conceptual.exception.handling/cs/source.cs#3)] +[!code-csharp[Conceptual.Exception.Handling#3](./snippets/best-practices/csharp/source.cs#3)] [!code-vb[Conceptual.Exception.Handling#3](~/samples/snippets/visualbasic/VS_Snippets_CLR/conceptual.exception.handling/vb/source.vb#3)] -The method to choose depends on how often you expect the event to occur. - -- Use exception handling if the event doesn't occur often, that is, if the event is truly exceptional and indicates an error, such as an unexpected end-of-file. When you use exception handling, less code is executed in normal conditions. +The approach to choose depends on how often you expect the event to occur. - Check for error conditions in code if the event happens routinely and could be considered part of normal execution. When you check for common error conditions, less code is executed because you avoid exceptions. +- Use exception handling if the event doesn't occur often, that is, if the event is truly exceptional and indicates an error, such as an unexpected end-of-file. When you use exception handling, less code is executed in normal conditions. -## Design classes so that exceptions can be avoided - -A class can provide methods or properties that enable you to avoid making a call that would trigger an exception. For example, a class provides methods that help determine whether the end of the file has been reached. These methods can be used to avoid the exception that's thrown if you read past the end of the file. The following example shows how to read to the end of a file without triggering an exception: - -[!code-cpp[Conceptual.Exception.Handling#5](~/samples/snippets/cpp/VS_Snippets_CLR/conceptual.exception.handling/cpp/source.cpp#5)] -[!code-csharp[Conceptual.Exception.Handling#5](~/samples/snippets/csharp/VS_Snippets_CLR/conceptual.exception.handling/cs/source.cs#5)] -[!code-vb[Conceptual.Exception.Handling#5](~/samples/snippets/visualbasic/VS_Snippets_CLR/conceptual.exception.handling/vb/source.vb#5)] - -Another way to avoid exceptions is to return null (or default) for most common error cases instead of throwing an exception. A common error case can be considered a normal flow of control. By returning null (or default) in these cases, you minimize the performance impact to an app. - -For value types, whether to use `Nullable` or default as your error indicator is something to consider for your app. By using `Nullable`, `default` becomes `null` instead of `Guid.Empty`. Sometimes, adding `Nullable` can make it clearer when a value is present or absent. Other times, adding `Nullable` can create extra cases to check that aren't necessary and only serve to create potential sources of errors. - -## Throw exceptions instead of returning an error code - -Exceptions ensure that failures don't go unnoticed because the calling code didn't check a return code. - -## Use the predefined .NET exception types - -Introduce a new exception class only when a predefined one doesn't apply. For example: - -- If a property set or method call isn't appropriate given the object's current state, throw an exception. -- If invalid parameters are passed, throw an exception or one of the predefined classes that derive from . - -## End exception class names with the word `Exception` - -When a custom exception is necessary, name it appropriately and derive it from the class. For example: - -[!code-cpp[Conceptual.Exception.Handling#4](~/samples/snippets/cpp/VS_Snippets_CLR/conceptual.exception.handling/cpp/source.cpp#4)] -[!code-csharp[Conceptual.Exception.Handling#4](~/samples/snippets/csharp/VS_Snippets_CLR/conceptual.exception.handling/cs/source.cs#4)] -[!code-vb[Conceptual.Exception.Handling#4](~/samples/snippets/visualbasic/VS_Snippets_CLR/conceptual.exception.handling/vb/source.vb#4)] - -## Include three constructors in custom exception classes - -Use at least the three common constructors when creating your own exception classes: the parameterless constructor, a constructor that takes a string message, and a constructor that takes a string message and an inner exception. - -- , which uses default values. -- , which accepts a string message. -- , which accepts a string message and an inner exception. - -For an example, see [How to: Create User-Defined Exceptions](how-to-create-user-defined-exceptions.md). - -## Ensure that exception data is available when code executes remotely - -When you create user-defined exceptions, ensure that the metadata for the exceptions is available to code that's executing remotely. - -For example, on .NET implementations that support app domains, exceptions might occur across app domains. Suppose app domain A creates app domain B, which executes code that throws an exception. For app domain A to properly catch and handle the exception, it must be able to find the assembly that contains the exception thrown by app domain B. If app domain B throws an exception that is contained in an assembly under its application base, but not under app domain A's application base, app domain A won't be able to find the exception, and the common language runtime will throw a exception. To avoid this situation, you can deploy the assembly that contains the exception information in either of two ways: - -- Put the assembly into a common application base shared by both app domains. -- If the domains don't share a common application base, sign the assembly that contains the exception information with a strong name and deploy the assembly into the global assembly cache. - -## Use grammatically correct error messages - -Write clear sentences and include ending punctuation. Each sentence in the string assigned to the property should end in a period. For example, "The log table has overflowed." would be an appropriate message string. - -## Include a localized string message in every exception - -The error message the user sees is derived from the property of the exception that was thrown, and not from the name of the exception class. Typically, you assign a value to the property by passing the message string to the `message` argument of an [Exception constructor](xref:System.Exception.%23ctor%2A). - -For localized applications, you should provide a localized message string for every exception that your application can throw. You use resource files to provide localized error messages. For information on localizing applications and retrieving localized strings, see the following articles: +.NET design patterns include alternative forms of error handling for situations when the performance cost of exceptions is prohibitive. For example, returns a Boolean, with an `out` parameter that contains the parsed valid integer upon success. has similar behavior for attempting to get a value from a dictionary. -- [How to: Create user-defined exceptions with localized exception messages](how-to-create-localized-exception-messages.md) -- [Resources in .NET apps](../../core/extensions/resources.md) -- - -## In custom exceptions, provide additional properties as needed +### Catch cancellation and asynchronous exceptions -Provide additional properties for an exception (in addition to the custom message string) only when there's a programmatic scenario where the additional information is useful. For example, the provides the property. +It's better to catch instead of , which derives from `OperationCanceledException`, when you call an asynchronous method. Many asynchronous methods throw an exception if cancellation is requested. These exceptions enable execution to be efficiently halted and the callstack to be unwound once a cancellation request is observed. -## Place throw statements so that the stack trace will be helpful +Asynchronous methods store exceptions that are thrown during execution in the task they return. If an exception is stored into the returned task, that exception will be thrown when the task is awaited. Usage exceptions, such as , are still thrown synchronously. For more information, see [Asynchronous exceptions](../../csharp/asynchronous-programming/index.md#asynchronous-exceptions). -The stack trace begins at the statement where the exception is thrown and ends at the `catch` statement that catches the exception. +### Design classes so that exceptions can be avoided -## Use exception builder methods +A class can provide methods or properties that enable you to avoid making a call that would trigger an exception. For example, the class provides methods that help determine whether the end of the file has been reached. You can call these methods to avoid the exception that's thrown if you read past the end of the file. The following example shows how to read to the end of a file without triggering an exception: -It's common for a class to throw the same exception from different places in its implementation. To avoid excessive code, use helper methods that create the exception and return it. For example: +[!code-csharp[Conceptual.Exception.Handling#5](./snippets/best-practices/csharp/source.cs#5)] +[!code-vb[Conceptual.Exception.Handling#5](~/samples/snippets/visualbasic/VS_Snippets_CLR/conceptual.exception.handling/vb/source.vb#5)] -[!code-cpp[Conceptual.Exception.Handling#6](~/samples/snippets/cpp/VS_Snippets_CLR/conceptual.exception.handling/cpp/source.cpp#6)] -[!code-csharp[Conceptual.Exception.Handling#6](~/samples/snippets/csharp/VS_Snippets_CLR/conceptual.exception.handling/cs/source.cs#6)] -[!code-vb[Conceptual.Exception.Handling#6](~/samples/snippets/visualbasic/VS_Snippets_CLR/conceptual.exception.handling/vb/source.vb#6)] +Another way to avoid exceptions is to return `null` (or default) for most common error cases instead of throwing an exception. A common error case can be considered a normal flow of control. By returning `null` (or default) in these cases, you minimize the performance impact to an app. -In some cases, it's more appropriate to use the exception's constructor to build the exception. An example is a global exception class such as . +For value types, consider whether to use `Nullable` or `default` as the error indicator for your app. By using `Nullable`, `default` becomes `null` instead of `Guid.Empty`. Sometimes, adding `Nullable` can make it clearer when a value is present or absent. Other times, adding `Nullable` can create extra cases to check that aren't necessary and only serve to create potential sources of errors. -## Restore state when methods don't complete due to exceptions +### Restore state when methods don't complete due to exceptions Callers should be able to assume that there are no side effects when an exception is thrown from a method. For example, if you have code that transfers money by withdrawing from one account and depositing in another account, and an exception is thrown while executing the deposit, you don't want the withdrawal to remain in effect. @@ -203,7 +148,7 @@ Catch ex As Exception End Try ``` -## Capture exceptions to rethrow later +### Capture exceptions to rethrow later To capture an exception and preserve its callstack to be able to rethrow it later, use the class. This class provides the following methods and properties (among others): @@ -249,6 +194,122 @@ File name: 'C:\temp\file.txt' at Example.ProcessFile.Main() in C:\repos\ConsoleApp1\Program.cs:line 24 ``` -## See also +## Throwing exceptions + +The following best practices concern how you throw exceptions: + +- [Use predefined exception types](#use-predefined-exception-types) +- [Use exception builder methods](#use-exception-builder-methods) +- [Include a localized string message](#include-a-localized-string-message) +- [Use proper grammar](#use-proper-grammar) +- [Place throw statements well](#place-throw-statements-well) +- [Rethrow to preserve stack details](#rethrow-to-preserve-stack-details) +- [Don't raise exceptions in finally clauses](#dont-raise-exceptions-in-finally-clauses) +- [Don't raise exceptions from unexpected places](#dont-raise-exceptions-from-unexpected-places) +- [Throw argument validation exceptions synchronously](#throw-argument-validation-exceptions-synchronously) + +### Use predefined exception types + +Introduce a new exception class only when a predefined one doesn't apply. For example: + +- If a property set or method call isn't appropriate given the object's current state, throw an exception. +- If invalid parameters are passed, throw an exception or one of the predefined classes that derive from . + +> [!NOTE] +> While it's best to use predefined exception types when possible, you shouldn't raise some *reserved* exception types, such as , , and . For more information, see [CA2201: Do not raise reserved exception types](../../fundamentals/code-analysis/quality-rules/ca2201.md). + +### Use exception builder methods + +It's common for a class to throw the same exception from different places in its implementation. To avoid excessive code, create a helper method that creates the exception and returns it. For example: + +[!code-csharp[Conceptual.Exception.Handling#6](./snippets/best-practices/csharp/source.cs#6)] +[!code-vb[Conceptual.Exception.Handling#6](~/samples/snippets/visualbasic/VS_Snippets_CLR/conceptual.exception.handling/vb/source.vb#6)] + +Some key .NET exception types have static methods that allocate and throw the exception. To make your code smaller and faster, use these methods whenever possible: + +- +- +- +- +- +- +- +- +- +- +- +- +- + +The following code analysis rules can help you find places in your code where you can take advantage of these static `throw` helpers: [CA1510](../../fundamentals/code-analysis/quality-rules/ca1510.md), [CA1511](../../fundamentals/code-analysis/quality-rules/ca1511.md), [CA1512](../../fundamentals/code-analysis/quality-rules/ca1512.md), and [CA1513](../../fundamentals/code-analysis/quality-rules/ca1513.md). + +If you're implementing an asynchronous method, call instead of checking if cancellation was requested and then constructing and throwing . For more information, see [CA2250](../../fundamentals/code-analysis/quality-rules/ca2250.md). + +### Include a localized string message + +The error message the user sees is derived from the property of the exception that was thrown, and not from the name of the exception class. Typically, you assign a value to the property by passing the message string to the `message` argument of an [Exception constructor](xref:System.Exception.%23ctor%2A). + +For localized applications, you should provide a localized message string for every exception that your application can throw. You use resource files to provide localized error messages. For information on localizing applications and retrieving localized strings, see the following articles: + +- [How to: Create user-defined exceptions with localized exception messages](how-to-create-localized-exception-messages.md) +- [Resources in .NET apps](../../core/extensions/resources.md) +- + +### Use proper grammar + +Write clear sentences and include ending punctuation. Each sentence in the string assigned to the property should end in a period. For example, "The log table has overflowed." uses correct grammar and punctuation. + +### Place throw statements well + +Place throw statements where the stack trace will be helpful. The stack trace begins at the statement where the exception is thrown and ends at the `catch` statement that catches the exception. + +### Rethrow to preserve stack details + +Once an exception is thrown, part of the information it carries is the stack trace. The stack trace is a list of the method call hierarchy that starts with the method that throws the exception and ends with the method that catches the exception. If an exception is rethrown by specifying the exception in the `throw` statement, the stack trace is restarted at the current method and the list of method calls between the original method that threw the exception and the current method is lost. To keep the original stack trace information with the exception, use the `throw` statement without specifying the exception. + +For more information, see [CA2200: Rethrow to preserve stack details](../../fundamentals/code-analysis/quality-rules/ca2200.md). + +### Don't raise exceptions in finally clauses + +For more information, see [CA2219: Do not raise exceptions in exception clauses](../../fundamentals/code-analysis/quality-rules/ca2219.md). + +### Don't raise exceptions from unexpected places + +Some methods, such as `Equals`, `GetHashCode`, and `ToString` methods, static constructors, and equality operators, shouldn't throw exceptions. For more information, see [CA1065](../../fundamentals/code-analysis/quality-rules/ca1065.md). + +### Throw argument validation exceptions synchronously + +In task-returning methods, we recommend that you validate arguments and throw any corresponding exceptions, such as and , before entering the asynchronous part of the method. Exceptions that are thrown in the asynchronous part of the method are stored in the returned task and don't emerge until, for example, the task is awaited. For more information, see [Exceptions in task-returning methods](../../csharp/fundamentals/exceptions/creating-and-throwing-exceptions.md#exceptions-in-task-returning-methods). + +## Custom exception types + +The following best practices concern custom exception types: + +- [End exception class names with `Exception`](#end-exception-class-names-with-exception) +- [Include three constructors](#include-three-constructors) +- [Provide additional properties as needed](#provide-additional-properties-as-needed) + +### End exception class names with `Exception` + +When a custom exception is necessary, name it appropriately and derive it from the class. For example: + +[!code-csharp[Conceptual.Exception.Handling#4](./snippets/best-practices/csharp/source.cs#4)] +[!code-vb[Conceptual.Exception.Handling#4](~/samples/snippets/visualbasic/VS_Snippets_CLR/conceptual.exception.handling/vb/source.vb#4)] + +### Include three constructors + +Use at least the three common constructors when creating your own exception classes: the parameterless constructor, a constructor that takes a string message, and a constructor that takes a string message and an inner exception. + +- , which uses default values. +- , which accepts a string message. +- , which accepts a string message and an inner exception. + +For an example, see [How to: Create user-defined exceptions](how-to-create-user-defined-exceptions.md). + +### Provide additional properties as needed + +Provide additional properties for an exception (in addition to the custom message string) only when there's a programmatic scenario where the additional information is useful. For example, the provides the property. + +### See also -- [Exceptions](index.md) +- [Design guidelines for exceptions](../design-guidelines/exceptions.md) diff --git a/docs/standard/exceptions/how-to-use-finally-blocks.md b/docs/standard/exceptions/how-to-use-finally-blocks.md index d4262d5a7220f..c6577eff8380a 100644 --- a/docs/standard/exceptions/how-to-use-finally-blocks.md +++ b/docs/standard/exceptions/how-to-use-finally-blocks.md @@ -18,7 +18,7 @@ ms.assetid: 4b9c0137-04af-4468-91d1-b9014df8ddd2 When an exception occurs, execution stops and control is given to the appropriate exception handler. This often means that lines of code you expect to be executed are bypassed. Some resource cleanup, such as closing a file, needs to be done even if an exception is thrown. To do this, you can use a `finally` block. A `finally` block always executes, regardless of whether an exception is thrown. -The following code example uses a `try`/`catch` block to catch an . The `Main` method creates two arrays and attempts to copy one to the other. The action generates an and the error is written to the console. The `finally` block executes regardless of the outcome of the copy action. +The following code example uses a `try`/`catch` block to catch an . The `Main` method creates two arrays and attempts to copy one to the other. The action generates an because `length` is specified as -1, and the error is written to the console. The `finally` block executes regardless of the outcome of the copy action. [!code-cpp[CodeTryCatchFinallyExample#3](../../../samples/snippets/cpp/VS_Snippets_CLR/CodeTryCatchFinallyExample/CPP/source2.cpp#3)] [!code-csharp[CodeTryCatchFinallyExample#3](../../../samples/snippets/csharp/VS_Snippets_CLR/CodeTryCatchFinallyExample/CS/source2.cs#3)] diff --git a/docs/standard/exceptions/snippets/best-practices/csharp/Project.csproj b/docs/standard/exceptions/snippets/best-practices/csharp/Project.csproj new file mode 100644 index 0000000000000..f704bf4988fa6 --- /dev/null +++ b/docs/standard/exceptions/snippets/best-practices/csharp/Project.csproj @@ -0,0 +1,10 @@ + + + + Exe + net8.0 + enable + enable + + + diff --git a/samples/snippets/csharp/VS_Snippets_CLR/conceptual.exception.handling/cs/source.cs b/docs/standard/exceptions/snippets/best-practices/csharp/source.cs similarity index 69% rename from samples/snippets/csharp/VS_Snippets_CLR/conceptual.exception.handling/cs/source.cs rename to docs/standard/exceptions/snippets/best-practices/csharp/source.cs index 4421cd16f2828..a15fb6188e352 100644 --- a/samples/snippets/csharp/VS_Snippets_CLR/conceptual.exception.handling/cs/source.cs +++ b/docs/standard/exceptions/snippets/best-practices/csharp/source.cs @@ -1,9 +1,4 @@ // -using System; -using System.IO; -using System.Data; -using System.Data.SqlClient; - public class FileReaderException : Exception { public FileReaderException(string description) : base(description) @@ -20,24 +15,16 @@ public enum ConnectionState public class DemoDBClient { - private ConnectionState state; - public DemoDBClient() { - state = ConnectionState.Open; + State = ConnectionState.Open; } - public ConnectionState State - { - get - { - return state; - } - } + public ConnectionState State { get; private set; } public void Close() { - state = ConnectionState.Closed; + State = ConnectionState.Closed; } } @@ -85,15 +72,9 @@ public static void Main() // class FileRead { - public void ReadAll(FileStream fileToRead) + public static void ReadAll(FileStream fileToRead) { - // This if statement is optional - // as it is very unlikely that - // the stream would ever be null. - if (fileToRead == null) - { - throw new ArgumentNullException(); - } + ArgumentNullException.ThrowIfNull(fileToRead); int b; @@ -114,24 +95,20 @@ public void ReadAll(FileStream fileToRead) // class FileReader { - private string fileName; + private readonly string _fileName; public FileReader(string path) { - fileName = path; + _fileName = path; } public byte[] Read(int bytes) { - byte[] results = FileUtils.ReadFromFile(fileName, bytes); - if (results == null) - { - throw NewFileIOException(); - } + byte[] results = FileUtils.ReadFromFile(_fileName, bytes) ?? throw NewFileIOException(); return results; } - FileReaderException NewFileIOException() + static FileReaderException NewFileIOException() { string description = "My NewFileIOException Description"; diff --git a/docs/standard/exceptions/snippets/how-to-use-finally-blocks/csharp/Project.csproj b/docs/standard/exceptions/snippets/how-to-use-finally-blocks/csharp/Project.csproj new file mode 100644 index 0000000000000..3897747193834 --- /dev/null +++ b/docs/standard/exceptions/snippets/how-to-use-finally-blocks/csharp/Project.csproj @@ -0,0 +1,10 @@ + + + + Exe + net6.0 + enable + enable + + + diff --git a/samples/snippets/csharp/VS_Snippets_CLR/CodeTryCatchFinallyExample/CS/source2.cs b/docs/standard/exceptions/snippets/how-to-use-finally-blocks/csharp/source2.cs similarity index 97% rename from samples/snippets/csharp/VS_Snippets_CLR/CodeTryCatchFinallyExample/CS/source2.cs rename to docs/standard/exceptions/snippets/how-to-use-finally-blocks/csharp/source2.cs index 52663b1407bf4..b73332e7dee12 100644 --- a/samples/snippets/csharp/VS_Snippets_CLR/CodeTryCatchFinallyExample/CS/source2.cs +++ b/docs/standard/exceptions/snippets/how-to-use-finally-blocks/csharp/source2.cs @@ -1,6 +1,4 @@ // -using System; - class ArgumentOutOfRangeExample { public static void Main() diff --git a/samples/snippets/csharp/VS_Snippets_CLR/Exception.Throwing/CS/throw.cs b/samples/snippets/csharp/VS_Snippets_CLR/Exception.Throwing/CS/throw.cs index 9b2e1513a8c84..1c8f51405540f 100644 --- a/samples/snippets/csharp/VS_Snippets_CLR/Exception.Throwing/CS/throw.cs +++ b/samples/snippets/csharp/VS_Snippets_CLR/Exception.Throwing/CS/throw.cs @@ -1,35 +1,33 @@ using System; using System.IO; -namespace Example +namespace Example; + +public class ProcessFile { - public class ProcessFile + public static void Main() { - public static void Main() + // + var fs = default(FileStream); + try { - // - var fs = default(FileStream); - try - { - // Opens a text tile. - fs = new FileStream(@"C:\temp\data.txt", FileMode.Open); - var sr = new StreamReader(fs); + // Open a text tile. + fs = new FileStream(@"C:\temp\data.txt", FileMode.Open); + var sr = new StreamReader(fs); - // A value is read from the file and output to the console. - string? line = sr.ReadLine(); - Console.WriteLine(line); - } - catch (FileNotFoundException e) - { - Console.WriteLine($"[Data File Missing] {e}"); - throw new FileNotFoundException(@"[data.txt not in c:\temp directory]", e); - } - finally - { - if (fs != null) - fs.Close(); - } - // + // Read a value from the file and output to the console. + string? line = sr.ReadLine(); + Console.WriteLine(line); + } + catch (FileNotFoundException e) + { + Console.WriteLine($"[Data File Missing] {e}"); + throw new FileNotFoundException(@"[data.txt not in c:\temp directory]", e); + } + finally + { + fs?.Close(); } + // } } diff --git a/samples/snippets/csharp/VS_Snippets_CLR/dg_exceptionDesign/cs/example1.cs b/samples/snippets/csharp/VS_Snippets_CLR/dg_exceptionDesign/cs/example1.cs deleted file mode 100644 index 70d59e9d4abc5..0000000000000 --- a/samples/snippets/csharp/VS_Snippets_CLR/dg_exceptionDesign/cs/example1.cs +++ /dev/null @@ -1,232 +0,0 @@ -using System; -using System.IO; -using System.Net; -using System.Runtime.Serialization; -using System.Collections.Generic; - -namespace Examples.DesignGuidelines.Exceptions -{ -// - public class BadExceptionHandlingExample1 - { - public void DoWork() - { - // Do some work that might throw exceptions. - } - public void MethodWithBadHandler() - { - try - { - DoWork(); - } - catch (Exception e) - { - // Handle the exception and - // continue executing. - } - } - } -// - -// - public class BadExceptionHandlingExample2 - { - public void DoWork() - { - // Do some work that might throw exceptions. - } - public void MethodWithBadHandler() - { - try - { - DoWork(); - } - catch (Exception e) - { - if (e is StackOverflowException || - e is OutOfMemoryException) - throw; - // Handle the exception and - // continue executing. - } - } - } -// - -public class ThrowExample1 -{ - // - public void DoWork(Object anObject) - { - // Do some work that might throw exceptions. - // - if (anObject == null) - { - throw new ArgumentNullException("anObject", - "Specify a non-null argument."); - } - // - // Do work with o. - } - // - // - public void MethodWithBadCatch(Object anObject) - { - try - { - DoWork(anObject); - } - catch (ArgumentNullException e) - { - System.Diagnostics.Debug.Write(e.Message); - // This is wrong. - throw e; - // Should be this: - // throw; - } - } - // - // - public void MethodWithBetterCatch() - { - try - { - DoWork(null); - } - catch (ArgumentNullException e) - { - System.Diagnostics.Debug.Write(e.Message); - throw; - } - } - // -} - -public class Wrapper -{ - public void EstablishConnection(){} - - // - public void SendMessages() - { - try - { - EstablishConnection(); - } - catch (System.Net.Sockets.SocketException e) - { - throw new CommunicationFailureException( - "Cannot access remote computer.", - e); - } - } - // - - IPAddress address = IPAddress.Loopback; - // - public IPAddress Address - { - get - { - return address; - } - set - { - if(value == null) - { - throw new ArgumentNullException("value"); - } - address = value; - } - } - // -} -public class CommunicationFailureException : Exception -{ - public CommunicationFailureException(string message) : base(message) - { - } - public CommunicationFailureException(string message, Exception innerException) - : base(message) - { - } -} - -public class BaseException: Exception{} - -// -public class NewException : BaseException, ISerializable -{ - public NewException() - { - // Add implementation. - } - public NewException(string message) - { - // Add implementation. - } - public NewException(string message, Exception inner) - { - // Add implementation. - } - - // This constructor is needed for serialization. - protected NewException(SerializationInfo info, StreamingContext context) - { - // Add implementation. - } -} -// -// -// -public class Doer -{ - // Method that can potential throw exceptions often. - public static void ProcessMessage(string message) - { - if (message == null) - { - throw new ArgumentNullException("message"); - } - } - // Other methods... -} -// - -// -public class Tester -{ - public static void TesterDoer(ICollection messages) - { - foreach (string message in messages) - { - // Test to ensure that the call - // won't cause the exception. - if (message != null) - { - Doer.ProcessMessage(message); - } - } - } -} -// -// - -public class BadParser -{ - // - Uri ParseUri(string uriValue, bool throwOnError) - // - {return new Uri("http://contoso.com");} -} - -public class TestMain -{ - public static void Main() - { - ThrowExample1 t = new ThrowExample1(); - // t.MethodWithBadCatch(); - // t.MethodWithBetterCatch(); - } -} -} diff --git a/samples/snippets/csharp/VS_Snippets_CLR/dg_exceptionDesign/cs/example2.cs b/samples/snippets/csharp/VS_Snippets_CLR/dg_exceptionDesign/cs/example2.cs index 4fc609a833108..65b2cf85ecb09 100644 --- a/samples/snippets/csharp/VS_Snippets_CLR/dg_exceptionDesign/cs/example2.cs +++ b/samples/snippets/csharp/VS_Snippets_CLR/dg_exceptionDesign/cs/example2.cs @@ -23,11 +23,10 @@ public class TestExample { public static void Main() { - EmployeeListNotFoundException e1, e2, e3; - Exception ex = new Exception(); + Exception ex = new(); - e1 = new EmployeeListNotFoundException(); - e2 = new EmployeeListNotFoundException("Hi!"); - e3 = new EmployeeListNotFoundException("Hi!", ex); + _ = new EmployeeListNotFoundException(); + _ = new EmployeeListNotFoundException("Hi!"); + _ = new EmployeeListNotFoundException("Hi!", ex); } }