Dan Bryant Dan Bryant - 1 year ago 81
C# Question

Using 'dynamic' in C# to implement Visitor Pattern

I have an application where I am performing an operation on a series of elements and the exact nature of the operation depends on the type of the element being operated upon. For reasons of encapsulation, it's not appropriate for the element to implement the operation; this means it can't be a virtual method on the element type and so 'standard' polymorphism doesn't work. I posed a previous question related to this and was informed that this was known as the Visitor Pattern.

I had previously always implemented this using an

if/elseif
dispatcher method based on the type of the object, then calling an appropriate implementation. Recently, however, I noticed that the same thing could be accomplishing using the
dynamic
keyword, like this:

private void ReconcileTips()
{
foreach (var step in _definition.Steps)
{
ReconcileTips((dynamic)step);
}
}

private void ReconcileTips(IBulkDispenseDefinition bulkDispense)
{
bulkDispense.TipType = ReconcileTip(bulkDispense.TipType);
}

private void ReconcileTips(ImportScreenDefinition importScreen)
{
foreach (var usage in importScreen.ReagentUsages)
usage.TipType = ReconcileTip(usage.TipType);
}

private void ReconcileTips(BuildScreenDefinition buildScreen)
{
foreach (var function in buildScreen.Functions)
function.TipType = ReconcileTip(function.TipType);
}


A similar pattern could be used for other operations parallel to the class structure, like creating view models for each element of
_definition.Steps
. The thought is that the compiler basically transforms this into the same
if/elseif
logic I wrote before, saving me the effort. So, a few questions:


  1. Are there any gotchas with the dynamic dispatching that I haven't considered? I believe this is equivalent to performing a series of
    if (x is TypeA) Do((TypeA)x) else...
    , but I could be wrong.

  2. Is this actually cleaner and easier to understand than a long
    if/elseif
    method?


Answer Source

Are there any gotchas with the dynamic dispatching that I haven't considered? I believe this is equivalent to performing a series of if (x is TypeA) Do((TypeA)x) else..., but I could be wrong.

The main gotcha would be if a type implements more than one interface in your visitor pattern - the compiler will probably pick the one you want, but it may not be the same choice you'd make if you use if (x is TypeA)/else if (x is TypeB) logic, as you'd control the order the checks occur.

Is this actually cleaner and easier to understand than a long if/elseif method?

I personally think so. This provides a very clean, fairly decently performing dispatch determined by the runtime type, and "just works." Hard to beat simple, short, clean code. Just make sure to (potentially) handle the case where you get a runtime error from the wrong type being passed in.

Recommended from our users: Dynamic Network Monitoring from WhatsUp Gold from IPSwitch. Free Download