Search code examples
c#disposeusing-statement

Will I still get the Dispose advanges, if I in a using, initialize with null?


I would like to refactor my SqlDataReader code, so it's using using..

SqlDataReader reader = null;
reader = xdCmd.ExecuteReader();
// use reader..

Can I use solution 1) where I declare the reader in the using and first later initialize it with a SqlDataReader, and still get the Dispose "features" using provides? Or do I need to do it as in solution 2), where the initialization happends right away, in the using? I would guess that 1) is fine, but I'm not sure.

1)

using (SqlDataReader reader = null)
{
    xdCmd.CommandText = $"select * from {tableName}";
    reader = xdCmd.ExecuteReader();
    // use reader..
}

2)

using (SqlDataReader reader = new SqlDataReader(new SqlCommand($"select * from {tableName}"), xdCon))
{
    reader = xdCmd.ExecuteReader();
    // use reader..
}

Solution

  • The C# language does not include syntax to express the concept of object "ownership" or lifetime management unlike Rust, so it's entirely up to an API's documentation to say if an object's constructor takes ownership of its arguments or not (and thus who gets to call .Dispose()). This is not something the C# compiler can determine for you. However .Dispose() implementations must be idempotent anyway so there is no harm in calling .Dispose() multiple (redundant) times.

    Just follow the C# idiomatic conventions of stacked using statements:

    using( SqlConnection c = new SqlConnection( connectionString ) )
    using( SqlCommand cmd = c.CreateCommand() )
    {
        await c.OpenAsync().ConfigureAwait(false);
    
        cmd.CommandText = "SELECT foo, bar FROM baz";
    
        using( SqlDataReader rdr = await cmd.ExecuteReaderAsync().ConfigureAwait(false) )
        {
            ...
        }
    }