John Lam claims that C#'s "using" blocks aren't "extensible to let us do arbitrary things". He shows us an example of doing arbitrary things in statement blocks in Ruby. I'll agree that his example is slick, using a continuation to yield control to the block, but there's certainly nothing keeping you from getting same functionality in C#. The "using" block is simply a mechanism that utilizes the Dispose pattern to do things when you're done with them. I've done everything from the standard releasing of resources to implementing reader/writer locks with them.
To speak to John's example, there's nothing keeping you from creating a wrapper or subclass that calls SetInfo in the Dispose method to accomplish the same thing. Or, you could create a generic factory pattern that uses delegates to define the creation and disposing actions:
public delegate T Creator<T>();
public class DisposingFactory<T> : IDisposable {
Creator<T> creator;
Action<T> disposeAction;
public DisposingFactory(Creator<T> creator, Action<T> disposeAction) {
this.creator = creator;
this.disposeAction = disposeAction;
}
bool valueCreated = false;
private T value;
public T Value {
get {
if (!valueCreated) {
value = creator();
}
return value;
}
}
public void Dispose() {
if (valueCreated) {
disposeAction(value);
}
}
}
This also incorporates thunk-like lazy creation. I'll admit to not having alot of Ruby experience, but it seems to me that "using" is every bit as "extensible" as far as executing code at the end of a block. Here's John's example using the above with some pseudo-code:
using (DisposingFactory<VirtualDirectory> factory = new DisposingFactory<VirtualDirectory>(
delegate() { return VirtualDirectory.CreateFromMoniker("some url"); },
delegate(VirtualDirectory value) { value.SetInfo(); })) {
factory.Value.AccessRead =
true;
factory.Path =
"c:\foo";
}
You could, of course, bake the delegates into a class to make it simpler. I suppose the most appropriate rebuttal to John's claims would be a wrapper class that takes care of it in the same way his example does, but I thought this example was a little more interesting.
John, I'd love to hear your feedback on this. I'm sure there's lots I could learn from you.
[Update] dasBlog swallowed my generics, so I had to fix them.