Friday, December 21, 2012

Using Dynamic Instead of Type Casting

Yesterday I was writing some NUnit tests for an MVC controller. My test was making sure that a property on the model being placed in the view had a property set correctly:

   1:  var sut = new MyController(fakeProvider);
   2:  var result = (ViewResult) sut.Index(id);
   3:  var model = result.Model;
   4:  Assert.That(model.MyProperty, Is.EqualTo(expectedValue);

Often type casting can be full of syntactic noise. I could refactor that code to remove a line:

   1:  var sut = new MyController(fakeProvider);
   2:  var model = ((ViewResult) sut.Index(id)).Model;
   3:  Assert.That(model.MyProperty, Is.EqualTo(expectedValue);

All those parenthesis on line two are like fingernails on a chalkboard to me. Luckily I was having a problem with the razor view when I was trying to preview the controller that resulted in me hacking away at my code until it looked like:

   1:  var sut = new MyController(fakeProvider);
   2:  dynamic result = sut.Index(id);
   3:  Assert.That(result.Model.MyProperty, Is.EqualTo(expectedValue);

I didn’t even notice until this morning when working on another action in the controller that I had removed the need for casting my ActionResult to a ViewResult in my test. What a happy accident. I suspect that the compiler is doing the type casting for me under the covers, but I leave ILDASM to @vcsjones, so I’ll never know for sure.

I am filing that little tidbit in my bag of tricks and will definitely be using that in the future.

2 comments:

  1. I also hate noisy type casting, but I've handled it differently and in ways that avoid some significant drawbacks to using "dynamic" like this.

    For example, I've created a class called "ActionResultWrapper" that exposes a typed action result (view, redirect, etc) based on the TView generic type and a typed model based on TModel.

    Then, I add an extension method to ActionResult that lets me do: Controller.Action(...).GetResult. This returns an instance of my wrapper class that has a View property already cast to ViewResult and a Model property already cast to Foo.

    There are a few benefits to this:

    1) There's no casting anywhere in my test code. I specify type arguments one type in the call to the helper.

    2) I get full intellisense, which you don't get with dynamic.

    3) I get better error handling. In your case, if something returns a redirect instead of a view, you'll get a runtime exception without a lot of detail. In a helper class you can do lots of things, such as throwing an exception like "The expected result was a View, but was actually a redirect to: ".

    4) I get compile time checking of my test code and full refactoring support. (If I rename a property of a view model, anything that asserts against it gets renamed as well)

    Bottom line: dynamic lets you avoid the cast but you lose intellisense, static code analysis, and get less useful failure messages if something goes bad.

    It takes an hour or two of coding to set up the framework I outline above but it's totally, totally worth it.

    ReplyDelete
  2. That is an interesting approach. I am not as concerned about intellisense or compile time checking, but the error handling and refactoring support are nice benefits.

    Are you saying you have a public static GetResult(this ActionResult) method? That does sound like an elegant solution.

    ReplyDelete

Follow me on App.net