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

limit disposable pattern #6785

Merged
merged 1 commit into from
Dec 13, 2022
Merged
Changes from all 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
19 changes: 5 additions & 14 deletions proposals/csharp-8.0/using.md
Original file line number Diff line number Diff line change
Expand Up @@ -102,12 +102,12 @@ Restrictions around `using` declaration:

### pattern-based using

The language will add the notion of a disposable pattern: that is a type which has an accessible
The language will add the notion of a disposable pattern for `ref struct` types: that is a `ref struct` which has an accessible
`Dispose` instance method. Types which fit the disposable pattern can participate in a `using`
statement or declaration without being required to implement `IDisposable`.

```csharp
class Resource
ref struct Resource
{
public void Dispose() { ... }
}
Expand All @@ -118,16 +118,8 @@ using (var r = new Resource())
}
```

This will allow developers to leverage `using` in a number of new scenarios:

- `ref struct`: These types can't implement interfaces today and hence can't participate in `using`
This will allow developers to leverage `using` for `ref struct` types. These types can't implement interfaces today and hence can't participate in `using`
statements.
- Extension methods will allow developers to augment types in other assemblies to participate
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I confirmed from the code (TryFindDisposePatternMethod) that extension methods don't count. Tagging @chsienki to confirm this was intentional and to fix the speclet.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yes, extension methods we're explicitly disallowed, even for ref structs. The decision being that it would have been legal to have an extension method called 'Dispose' that previously wouldn't have been called if you used the type in a foreach. With the extension method lookup, it would now get called, which was considered too big a breaking change.

LDM notes are here: https://github.com/dotnet/csharplang/blob/3c8559f186d4c5df5d1299b0eaa4e139ae130ab6/meetings/2018/LDM-2018-12-12.md#when-we-start-recognizing-pattern-dispose-do-we-call-it-in-foreach

in `using` statements.

In the situation where a type can be implicitly converted to `IDisposable` and also fits the
disposable pattern, then `IDisposable` will be preferred. While this takes the opposite approach
of `foreach` (pattern preferred over interface) it is necessary for backwards compatibility.

The same restrictions from a traditional `using` statement apply here as well: local variables
declared in the `using` are read-only, a `null` value will not cause an exception to be thrown,
Expand All @@ -146,9 +138,8 @@ etc ... The code generation will be different only in that there will not be a c
}
```

In order to fit the disposable pattern the `Dispose` method must be accessible, parameterless and have
a `void` return type. There are no other restrictions. This explicitly means that extension methods
can be used here.
In order to fit the disposable pattern the `Dispose` method must be an accessible instance member, parameterless and have
a `void` return type. It cannot be an extension method.

## Considerations

Expand Down