Реструктуризация, чтобы не использовать исключения путем определения того, какой метод реализован - PullRequest
2 голосов
/ 06 января 2010

Итак, я разрабатываю что-то, что работает с dynamic переменными, используя C # 4. И я нахожусь в ситуации, когда у меня есть две переменные a и b, и я знаю , что либо a.Foo(b) или b.Foo(a) определяется. Однако я не знаю, какой именно сейчас я использую что-то вроде этого:

dynamic a, b, result;
...

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

Что ужасно (не только неэлегично, но и очень медленно, так как есть вероятность 0,5 * поднять Exception и произвести трассировку стека). Я мог бы использовать отражение, но я ожидаю, что это будет довольно медленно.

Так есть ли лучший способ?


Так вот в чем проблема ... но я также объясню контекст, так как думаю, что есть хороший шанс, что есть лучший способ справиться со всей ситуацией. По сути, я строю деревья выражений (используя собственную структуру узлов), которые работают со многими различными типами данных.

Если вы считаете выражение 1+'2', значения a и b являются операндами 1 и '2'. Если я хочу оценить узел +, который имеет поддеревья a и b, то любой операнд может содержать метод для Add типа другого операнда. То есть, либо a.Add(b) реализовано, либо b.Add(a) реализовано.

Я могу думать только об использовании отражения, описанного выше метода, или создании дублирующих функций в обоих типах a и b для моделирования симметрии.

Ответы [ 3 ]

1 голос
/ 06 января 2010

Microsoft рекомендует вам сделать это, предоставив свойство или метод IsImplemented, которые вы сможете вызвать, чтобы определить, какой из ваших объектов реализует Foo перед вызовом одного из них, только чтобы выяснить, т.

Затраты на обработку исключений не огромные , но они заметны, и вам действительно следует избегать исключений, если вы не обрабатываете исключительный сценарий. В этом основное отличие исключений и кодов ошибок от C / C ++.

Итак, добавьте свойство IsFooImplemented или что-то в этом роде. Это спасет вас от исключения.

0 голосов
/ 06 января 2010

Я думаю (как сказал Эд), я бы решил эту проблему, используя интерфейс (т.е. IResolve), который применяется к каждому из узлов в вашей иерархии:

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;
   }
}

Проблема в том, что у вас будет неоднозначность с разрешением интерфейса. Это не идеально, и мне не нравится отсутствие формальной языковой нотации (то есть детерминизма дерева), но это может быть место для начала.

0 голосов
/ 06 января 2010

Как насчет преобразования обоих операндов в правильное число, прежде чем пытаться добавить их?

Т.е., используйте что-то вроде System.Convert, как описано здесь , затем:

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

result = a2 + b2;
...