-
Notifications
You must be signed in to change notification settings - Fork 4.7k
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
TcpListener should implement IDisposable #63114
Comments
Tagging subscribers to this area: @dotnet/ncl Issue DetailsTcpListener is essentially a convenience wrapper around a Socket in listen mode. Sockets are disposable, but TcpListener is not. Instead, you are expected to call the Stop() method. Implementing IDisposable enables "using" syntax and matches common library practice. Consider that the sample code for TcpListener explicitly uses a try/finally to ensure that Stop() is called properly: https://docs.microsoft.com/en-us/dotnet/api/system.net.sockets.tcplistener?view=net-6.0 See also https://stackoverflow.com/questions/33667149/why-tcplistener-does-not-implement-idisposable
|
Note that if we implement this, we should also ensure that operations like Accept throw ObjectDisposedException if the TcpListener is disposed, for consistency with how IDisposable works in general and with Socket in particular. And we should disallow Start() after Dispose() -- today we allow you to call Start() again after Stop(), which isn't super useful. In other words, Dispose() is not simply a synonym for Stop(). Note that today, if you call Accept after Stop(), you get an InvalidOperationException with the message "You must call the Start() method before calling this method." -- which is not particularly correct in describing the condition. So adding Dispose and using it instead of Stop() would actually result in a more useful exception here. We could also consider deprecating Stop. See also #63115. |
Take it further: we should consider deprecating the entirety of |
I have some thoughts on that, I'll file another issue on it. I do think there's some value in having simple, high-level TCP APIs that allow you avoid dealing with Socket directly. But I think TcpClient and TcpListener don't do a great job of this -- TcpClient in particular. |
Triage: |
Adding Because the type has already shipped, has existed for a long time, and has very few derived types in the wild, we're okay with saying it doesn't need to bother with the Basic Dispose Pattern ( namespace System.Net.Sockets
{
public class TcpListener
+ : IDisposable
{
+ public void Dispose() => Stop();
}
} |
What is the expected behaviour if Dispose is called twice? When implementing the Dispose pattern, there is: “A block for conditional return if object is already disposed.” protected virtual void Dispose(bool disposing)
{
if (_disposed)
{
return;
}
if (disposing)
{
// TODO: dispose managed state (managed objects).
}
// TODO: free unmanaged resources (unmanaged objects) and override a finalizer below.
// TODO: set large fields to null.
_disposed = true;
} |
Same as Stop; it ends up being a nop if you call it twice in a row. |
Does adding the The specific breaking change I'm referring to occurs when a project has AnalysisMode set to |
No
Analyzers can flag all sorts of things, and the default severity for CA2000 is off. If someone chooses to enable it as an error and it flags something that breaks their build, that's on them. |
EDITED 3/14/2022 by @stephentoub:
TcpListener is essentially a convenience wrapper around a Socket in listen mode. Sockets are disposable, but TcpListener is not. Instead, you are expected to call the Stop() method.
Implementing IDisposable enables "using" syntax and matches common library practice.
Consider that the sample code for TcpListener explicitly uses a try/finally to ensure that Stop() is called properly: https://docs.microsoft.com/en-us/dotnet/api/system.net.sockets.tcplistener?view=net-6.0
See also https://stackoverflow.com/questions/33667149/why-tcplistener-does-not-implement-idisposable
The text was updated successfully, but these errors were encountered: