More info on ‘using’ and resource management


Joe Duffy (PM on the CLR team) posted to my blog about the whole using/resource management subject.  Being an cool and froody guy (who i may or may not have ever met) he linked back to a great post of his own on the subject *and* included even more information on the subject.  I’m going to repost his post here (since formatting of comments sucks on Community Server) so you can read it, and i also recommend you read his blog since it’s chock full of good content.


— (the following is written by Joe) —


I cover this in fair detail in my article, which I was happy to notice somebody already linked to!


This is a problem we really want to solve in Orcas. I noted a couple possible solutions at the bottom of the article. I had a few other speculations, but after conversations w/ Chris Brumme, I realized most of them were crap and we’d never recommend people write their code that way (nevermind have C# spit the code).


For example,


ExpressionType temp = null;
try {
try {
} finally {
temp = /*async-exception gets held up if triggered here*/ expression;
}
/* …and actually throws here */
statement
} finally {
if (temp != null) {
((IDisposable)temp).Dispose();
}
}

will ensure that an async exception won’t get raised, since we hold off on processing them during finally block execution. We also don’t execute them while you’re in a CER, running some opaque unmanaged code, and a few other corner scenarios. But holding up an async abort is a pretty rude thing to do, especially if you intend to block inside of it.


Further, you could imagine a class like


static class ReliableFactory {
public static void New<T>(out T created) where T : new() {
try {
} finally {
created = new T();
}
}
}

which would enable you to write


ExpressionType temp = null;
try {
ReliableFactory.New<ExpressionType>(out temp);
/* similar to above, an async exception won’t prevent the out assignment to temp */
statement
} finally {
if (temp != null) {
((IDisposable)temp).Dispose();
}
}

But this is fairly hokey.


I really hope we solve this problem in Orcas. But there’s quite a bit to do with Dispose that needs a fixin’, too. 🙂


Comments (5)

  1. What about something that took a delegate instead of a where T: new? Then you could use anonymous methods, and locals, etc.

    Something like this:

    public delegate T Creator<T>();

    public static class ReliableFactory {

    public static T Create<T>(Creator<T> create) {

    try { }

    finally {

    return create();

    }

    }

    }

    class C {

    void F() {

    using (ReliableFactory.Create(delegate { expression here); })) {

    // stuff.

    }

    }

    }

  2. Wait, that won’t work. (because the assignment will still not be protected by the finally.

    How about:

    public delegate T Creator<T>();

    public static class ReliableFactory {

    public static IDisposable Create<T>(out T temp, Creator<T> create) where T : IDisposable {

    try { }

    finally {

    temp = create();

    return null;

    }

    }

    }

    class C {

    void F() {

    using (IDisposable use = null, ignore = ReliableFactory.Create(out use, delegate { new LayoutTransaction(this, this, PropertyNames.Dock); })) {

    // stuff.

    }

    }

    }

  3. And the above would only work if the compiler changed the code gen so that the expression and assignment happen inside the try block.

  4. Ivailo says:

    Your blog is realy very interesting. http://www.g888.com