Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Refresh exceptions best practices #40688

Merged
merged 5 commits into from
May 1, 2024
Merged
Show file tree
Hide file tree
Changes from 2 commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -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 <xref:System.Exception?displayProperty=nameWithType>.

You can use the built-in exception classes, for example, <xref:System.ArgumentOutOfRangeException> or <xref:System.InvalidOperationException>. .NET also provides the helper methods to throw exceptions in certain conditions: <xref:System.ArgumentNullException.ThrowIfNull%2A?displayProperty=nameWithType> and <xref:System.ArgumentException.ThrowIfNullOrEmpty%2A?displayProperty=nameWithType>. You can also define your own exception classes that derive from <xref:System.Exception?displayProperty=nameWithType>. 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, <xref:System.ArgumentOutOfRangeException> or <xref:System.InvalidOperationException>. .NET also provides the following helper methods to throw exceptions in certain conditions: <xref:System.ArgumentNullException.ThrowIfNull%2A?displayProperty=nameWithType> and <xref:System.ArgumentException.ThrowIfNullOrEmpty%2A?displayProperty=nameWithType>. You can also define your own exception classes that derive from <xref:System.Exception?displayProperty=nameWithType>. 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:

Expand Down
2 changes: 1 addition & 1 deletion docs/csharp/nullable-references.md
Original file line number Diff line number Diff line change
Expand Up @@ -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 <xref:System.Nullable%601?displayProperty=nameWithType>, and nullable reference types are implemented by attributes read by the compiler. For example, `string?` and `string` are both represented by the same type: <xref:System.String?displayProperty=nameWithType>. However, `int?` and `int` are represented by `System.Nullable<System.Int32>` and <xref:System.Int32?displayProperty=nameWithType>, 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 <xref:System.ArgumentNullException.ThrowIfNull%2A?displayProperty=nameWithType> 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 <xref:System.ArgumentNullException.ThrowIfNull%2A?displayProperty=nameWithType> 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).
Expand Down
70 changes: 27 additions & 43 deletions docs/fundamentals/code-analysis/quality-rules/ca1065.md
Original file line number Diff line number Diff line change
Expand Up @@ -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:

- <xref:System.InvalidOperationException?displayProperty=fullName> and all derivatives (including <xref:System.ObjectDisposedException?displayProperty=fullName>)

- <xref:System.NotSupportedException?displayProperty=fullName> and all derivatives

- <xref:System.ArgumentException?displayProperty=fullName> (only from indexed get)

- <xref:System.Collections.Generic.KeyNotFoundException?displayProperty=fullName> (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:

- <xref:System.InvalidOperationException?displayProperty=fullName> and all derivatives (including <xref:System.ObjectDisposedException?displayProperty=fullName>)

- <xref:System.NotSupportedException?displayProperty=fullName> and all derivatives

- <xref:System.ArgumentException?displayProperty=fullName> and derivatives

### Equals Methods
### Equals methods

The following **Equals** methods should not throw exceptions:

- <xref:System.Object.Equals%2A?displayProperty=fullName>

- <xref:System.IEquatable%601.Equals%2A?displayProperty=fullName>

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 <xref:System.ArgumentException>.
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 <xref:System.ArgumentException>.

### GetHashCode Methods
### GetHashCode methods

The following **GetHashCode** methods should usually not throw exceptions:
The following `GetHashCode` methods should usually not throw exceptions:

- <xref:System.Object.GetHashCode%2A?displayProperty=fullName>

- <xref:System.Collections.IEqualityComparer.GetHashCode%2A?displayProperty=fullName>

**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 <xref:System.ArgumentException>. However, **Object.GetHashCode** should never throw an exception.
The versions of `GetHashCode` that take an argument can throw an <xref:System.ArgumentException>. However, `Object.GetHashCode` should never throw an exception.

### ToString Methods
### ToString methods

The debugger uses <xref:System.Object.ToString%2A?displayProperty=fullName> 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 <xref:System.Object.ToString%2A?displayProperty=fullName> 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 <xref:System.IDisposable.Dispose%2A?displayProperty=fullName> 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 <xref:System.IDisposable.Dispose%2A?displayProperty=fullName> 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.

Expand Down
2 changes: 1 addition & 1 deletion docs/fundamentals/code-analysis/quality-rules/ca2200.md
Original file line number Diff line number Diff line change
Expand Up @@ -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":::

Expand Down
4 changes: 1 addition & 3 deletions docs/fundamentals/code-analysis/quality-rules/ca2208.md
Original file line number Diff line number Diff line change
Expand Up @@ -28,10 +28,8 @@ dev_langs:

When a method has a parameter, and it throws an exception type that is, or derives from, <xref:System.ArgumentException>, 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, <xref:System.ArgumentException> 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, <xref:System.ArgumentException> 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, <xref:System.ArgumentException>.

- One of the parameters' names is passed for the `message` argument of the constructor of exception type that is, or derives from, <xref:System.ArgumentException>.

## Rule description
Expand Down
Loading
Loading