4

Consider the following (Microsoft-sanctioned) code:

<% using (Html.Form<HomeController>(action=>action.Index())) { %>

    <input type="text" id="search" />

    <input type="button" value="Submit" />

<% } %>

The using statement has but one purpose here: to add a </form> tag to the end of the generated HTML.

This feels dirty to me, for what I hope are obvious reasons:

  1. It's not using's raison d'etre.
  2. It deliberately causes side-effects.
  3. It's not intuitive that Html.Form would implement IDisposable.
  4. The using statement is not actually required, but Html.Form will break without it (unless you emit </form> yourself, which kinda misses the whole point).

This is not the only abuse that people have heaped onto the using pattern.

The question is, is there a viable alternative that provides the same stylistic/readability benefits as using, without making you feel like taking a shower afterwards?

6
  • I suspect that the Html.Form needs something more general nature. Not in this particular cases, but in general, a long running Html.Form would indicate that the subclasses can also have the same characteristic. With long running time, you saves lot of resources that you would use re-loading data and info into the Html.Form. Don't underestimate this cost, you will be surprised that some forms look like they can load easily, but they do not. – InformedA Aug 26 '14 at 18:12
  • 2
    To be honest when I first saw this specific use I was like "omg, that is a brilliant way to stretch the using concept." – Wyatt Barnett Aug 26 '14 at 18:25
  • @WyattBarnett: It has its charms. It's main disadvantage is that, if you're the next person reading the code, you need to know ahead of time that the pattern can be abused in this way. – Robert Harvey Aug 26 '14 at 18:27
  • @RobertHarvey -- it really depends on how you look at IDisposable. If you view it as some sort of abstraction around a proverbial unit of work then this makes loads of sense. If you are into the underlying resource disposal semantics then I certainly see your point. – Wyatt Barnett Aug 26 '14 at 23:40
  • Asking for a "better" alternative seems a bit subjective. – Chad Johnson Dec 16 '15 at 19:01
4

No, not in .NET currently.

using (by design) is the only thing that's guaranteed to have that sort of deterministic two-part execution that you can actually work with. (lock does too, but it doesn't expose anything you can hook into - and would be dirtier)

AoP solutions can maybe help, but I've not seen any that work well at the sub-function level, let alone in html templates.

There's the option of passing an anonymous delegate into a function (which then executes the lambda and disposes of the resource), but that's ugly:

Using.Transaction(new Resource(), ()=>{
  Foo();
  Bar();
});

And it has some limitations:

  • The compiler won't enforce that the resource is a previously undeclared resource like using blocks do.
  • You can't exit the lambda unconventionally like you can a using block (via return, break, continue, yield, goto)
    • (though the yield case is a known language bug and the other non-return cases are highly distasteful)
  • You can't access ref/out params from the lambda.
  • You can't use unsafe code in the lambda.
  • You can't "chain" the using blocks nicely.

Most of these can be circumvented by using named methods rather than anonymous, but that leads to its own problems.

11
  • 1
    Hmm... The situation would be better if IDisposable were named something more general-nature, like ITransaction. – Robert Harvey Aug 26 '14 at 17:31
  • What I was kinda after was some code that could be written that achieves the same purpose... I envision a higher-order wrapper function that takes a function as its parameter, but I'm not sure that would be as clean as using IDisposable. – Robert Harvey Aug 26 '14 at 17:42
  • @RobertHarvey - and how would you tell the code where to close the form? Delegates are used in some cases for that sort of thing in some cases, but the problem here is scoping the open/close. There may be some trickery that the new async/await stuff can do, but I've not seen it - and I expect it would not be as readable. – Telastyn Aug 26 '14 at 17:47
  • @Telastyn A function that does something like try { action(resource); } finally { resource.Dispose(); } where resource and action are arguments would do the trick, wouldn't it? – Doval Aug 26 '14 at 17:54
  • 1
    @Doval - added via edit. – Telastyn Aug 26 '14 at 18:23

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.