How to return an object depending on the chain of use of operators?

I would like to write a method similar to this:

C Make()
{
    using (var a = new A())
    using (var b = new B(a))
    {
        return new C(b);
    }
}

This is bad, because when the method returns, it cstores a reference to the located object.

Note that:

  • Aimplements IDisposable.
  • Bimplements IDisposable.
  • cdoes NOT implement IDisposable, as the author cstated that he c does not accept responsibility B.
+4
source share
3 answers

Your situation is very similar to what I sometimes saw when querying the database. In an attempt to separate the logic, you sometimes see the code as follows:

var reader = ExecuteSQL("SELECT ...");
while (reader.Read()) // <-- this fails, because the connection is closed.
{
    // process row...
}

public SqlDataReader ExecuteSQL(string sql)
{
    using (SqlConnection conn = new SqlConnection("..."))
    {
        conn.Open();
        using (SqlCommand cmd = new SqlCommand(sql, conn))
        {
            return cmd.ExecuteReader();
        }
    }
}

But, of course, this cannot work, because by the time the SqlDataReadermethod returns, the ExecuteSQLconnection has already been closed (deleted).

, , :

ExecuteSQL(reader => {
    // write code that reads from the SqlDataReader here.
});

public void ExecuteSQL(string sql, Action<SqlDataReader> processRow)
{
    using (SqlConnection conn = new SqlConnection("..."))
    {
        conn.Open();
        using (SqlCommand cmd = new SqlCommand(sql, conn))
        {
            using (SqlDataReader reader = cmd.ExecuteReader())
            {
                while (reader.Read())
                {
                    processRow(reader);
                }
            }
        }
    }
}

, , - ? - :

MakeAndProcess(c => {
    // write code that uses C here.
    // This will work, because A and B are not disposed yet.
});

public void MakeAndProcess(Action<C> processC)
{
    using (var a = new A())
    using (var b = new B(a))
    {
        processC(new C(b));
    }
}
0

, . .

, , ,

C , C b.

, , . , , a b C.

. Make() , b; b, C. , IDisposable a, b C C .

C, , b. .NET. ., , XmlReaderSettings.CloseInput.

+3

, a b .

, a b, - . , , C , , , a b, , :

class C {
    private readonly string x;
    private readonly int y;
    public C(B b) {
        // Using b here is OK
        x = b.X;
        y = b.Y;
        // We are done with b, so when b is disposed, C will not break
    }
}

, C b , , C

C, IDisposable, b , C :

class WrapC : IDisposable {
    private readonly B b;
    public C C { get; private set; }
    public WrapC (B b) {
        this.b = b;
        C = new C(b);
    }
    public void Dispose() {
        b.Dispose();
    }
}

Remove the instructions usingfor band delete WrapCwhen you are done with it.

+2
source

All Articles