views:

58

answers:

3

So I'm developing something that works on dynamic variables using C# 4. And I'm in a situation where I have two variables a and b and I know that either a.Foo(b) or b.Foo(a) is defined. However I don't know which so at the moment I use something like this:

dynamic a, b, result;
...

try
{
    result = a.Foo(b);
}
catch
{
    result = b.Foo(a);
}

Which is horrible (not only is it inelegant but it's very slow since there is around a 0.5 probability of raising an Exception and producing a stack trace). I could use reflection but I expect that'd be quite slow too.

So is there a better way?


So that's the problem... but I'll also explain the context since I think there's a good chance there's a better way to handle the whole situation. Essentially I am building expression trees (using my own node structure) that work with many different datatypes.

If you consider the expression 1+'2', the a and b values are the operands 1 and '2'. If I want to evaluate the + node, which has the sub-trees a and b, then either operand may contain a method to Add the other operand's type to it. That is, either a.Add(b) is implemented or b.Add(a) is implemented.

I can only think of using reflection, the method above, or producing duplicate functions in both types of a and b to model the symmetry.

+1  A: 

Microsoft would recommend that you do it by providing an IsImplemented property or method, which you should be able to call to determine which of your objects implements Foo before calling one of them, only to find that it doesn't.

The overhead of exception handling isn't huge, but it is noticeable, and you should really avoid exceptions unless you're handling an exceptional scenario. This is a major difference between exceptions and error codes from C/C++.

So, add an IsFooImplemented property or something like that. It'll save you an exception.

Ed Altorfer
The problem is that a.Foo might be implemented but simply not support b's type.
So provide a method IsFooImplemented(Type targetType). It's hard to give you a good answer without a more in-depth description of what you're doing and what your classes look like.
Ed Altorfer
A: 

How about converting both operands to a proper number before trying to add them?

I.e., use something like System.Convert as described here, then:

dynamic a2 = DoConvertToInteger(a);
dynamic b2 = DoConvertToInteger(b);

result = a2 + b2;
Seth
I can't do that since '2'+'2' = '22'.
GrayWizardx
A: 

I think (like Ed said) I would resolve this by using a Interface (i.e. IResolve), which is applied to each of the nodes in your hierarchy:

Interface IResolve {
   IResolve Resolve();
   object Value { get; }
   bool IsResolved { get; }
}

class Add : IResolve {
   List<IResolve> entities;

   protected IResolve doMyAddLogic(IResolve lvalue, IResolve rvalue) {
       return new ResolvedNodeValue(lvalue.Value + rvalue.Value);
   }

   public IResolve Resolve() {
      IResolve result = null;

      foreach(var child in entities) { 
         result = doMyAddLogic(result, child.Resolve());
      }

      return result;
   }
}

The problem is that you will have ambiguity with the resolution being behind an Interface. Its not perfect, and I dont like the lack of formal language notation (i.e. determinism of the tree), but it might be a place to start.

GrayWizardx