Home > database >  Will my c# 8.0 using declaration dispose my object correctly? When is it disposed?
Will my c# 8.0 using declaration dispose my object correctly? When is it disposed?

Time:04-21

I'm calling the following method in a loop while it is true, which leads to automatic reconnection. Since I'm using the using keyword, does it dispose the ClientWebSocket on each try/catch return false or it only disposes it if it reaches the end of ConnectAsync?

private async Task<bool> ConnectAsync(CancellationToken cancellationToken)
{
    using var clientWebSocket = new ClientWebSocket(); // TODO: Check if it's actually disposed
    _clientWebSocket = clientWebSocket;

    try
    {
        await clientWebSocket.ConnectAsync(new Uri(_url), cancellationToken);
    }
    catch
    {
        return false;
    }

    try
    {
        while (clientWebSocket.State == WebSocketState.Open && !cancellationToken.IsCancellationRequested)
        {
            var bytesReceived = new ArraySegment<byte>(new byte[1024]);
            var receiveResult = await clientWebSocket.ReceiveAsync(bytesReceived, cancellationToken);
            var message = Encoding.UTF8.GetString(bytesReceived.Array, 0, receiveResult.Count);
            
            ...
        }
    }
    catch
    {
        return false;
    }

    try
    {
        if (clientWebSocket.State == WebSocketState.Open)
        {
            await clientWebSocket.CloseAsync(WebSocketCloseStatus.NormalClosure, "bye", CancellationToken.None);
        }
    }
    catch
    {
        return false;
    }

    return true;
}

CodePudding user response:

using var clientWebSocket = new ClientWebSocket(); is just syntactical sugar, it's short hand for:

private async Task<bool> ConnectAsync(CancellationToken cancellationToken)
{
    using( var clientWebSocket = new ClientWebSocket())
    {
        _clientWebSocket = clientWebSocket;

        try
        {
            await clientWebSocket.ConnectAsync(new Uri(_url), cancellationToken);
        }
        catch
        {
            return false;
        }

        try
        {
            while (clientWebSocket.State == WebSocketState.Open && !cancellationToken.IsCancellationRequested)
            {
                var bytesReceived = new ArraySegment<byte>(new byte[1024]);
                var receiveResult = await clientWebSocket.ReceiveAsync(bytesReceived, cancellationToken);
                var message = Encoding.UTF8.GetString(bytesReceived.Array, 0, receiveResult.Count);
                
                ...
            }
        }
        catch
        {
            return false;
        }

        try
        {
            if (clientWebSocket.State == WebSocketState.Open)
            {
                await clientWebSocket.CloseAsync(WebSocketCloseStatus.NormalClosure, "bye", CancellationToken.None);
            }
        }
        catch
        {
            return false;
        }

        return true;

    }
}

which is short hand for:

private async Task<bool> ConnectAsync(CancellationToken cancellationToken)
{
    var clientWebSocket = new ClientWebSocket();
    try
    {
        _clientWebSocket = clientWebSocket;

        try
        {
            await clientWebSocket.ConnectAsync(new Uri(_url), cancellationToken);
        }
        catch
        {
            return false;
        }

        try
        {
            while (clientWebSocket.State == WebSocketState.Open && !cancellationToken.IsCancellationRequested)
            {
                var bytesReceived = new ArraySegment<byte>(new byte[1024]);
                var receiveResult = await clientWebSocket.ReceiveAsync(bytesReceived, cancellationToken);
                var message = Encoding.UTF8.GetString(bytesReceived.Array, 0, receiveResult.Count);
                
                ...
            }
        }
        catch
        {
            return false;
        }

        try
        {
            if (clientWebSocket.State == WebSocketState.Open)
            {
                await clientWebSocket.CloseAsync(WebSocketCloseStatus.NormalClosure, "bye", CancellationToken.None);
            }
        }
        catch
        {
            return false;
        }

        return true;

    }
    finally
    {
        if (clientWebSocket != null) {
            ((IDisposable)clientWebSocket).Dispose();  
        }
    }
}

I think it's also worth highlighting this comment:

I'm more worried that you're disposing something that you've assigned to the field _clientWebSocket

clientWebSocket is going to get disposed, but because you assign _clientWebSocket to this (_clientWebSocket = clientWebSocket;), the object that varibale is pointing at will get disposed as well! They are the same thing. They reference each other. I'd imagine this is not what you want to happen here, but it's hard to tell from the code you've shared.

CodePudding user response:

The using declaration calls the Dispose method on the object in the correct way when it goes out of scope. From: https://docs.microsoft.com/en-us/dotnet/csharp/language-reference/keywords/using-statement#remarks

So, in short. When the method returns it will dispose of the using declaration.

If you want to test this you can create a class that inherits ClientWebSocket and you can create your own dispose override that does some logging.

  • Related