Это ошибка ExpressionTrees? # 2 - PullRequest
10 голосов
/ 09 ноября 2009

Похоже, что компилятор ExpressionTrees должен быть близок со спецификацией C # во многих режимах, но в отличие от C # нет поддержки преобразования из decimal в любой enum-type:

using System;
using System.Linq.Expressions;

class Program
{
  static void Main()
  {
    Func<decimal, ConsoleColor> converter1 = x => (ConsoleColor) x;
    ConsoleColor c1 = converter1(7m); // fine

    Expression<Func<decimal, ConsoleColor>> expr = x => (ConsoleColor) x;

    // System.InvalidOperationException was unhandled
    // No coercion operator is defined between types
    // 'System.Decimal' and 'System.ConsoleColor'.

    Func<decimal, ConsoleColor> converter2 = expr.Compile();

    ConsoleColor c2 = converter2(7m);
  }
}

Существуют и другие редко используемые явные преобразования C #, такие как double -> enum-type, которые работают, как описано в спецификации C #, но не decimal -> enum-type. Это ошибка?

Ответы [ 2 ]

16 голосов
/ 09 ноября 2009

Вероятно, это ошибка, и, вероятно, это моя вина. Извините за это.

Правильное получение десятичных преобразований было одной из самых сложных частей построения правильного кода дерева выражений в компиляторе и во время выполнения, поскольку десятичные преобразования фактически выполняются как пользовательские преобразования во время выполнения, но рассматриваются как встроенные преобразования компилятором . Десятичный является единственным типом с этим свойством, и поэтому в этих случаях в анализаторе есть все виды специального оборудования. На самом деле, в анализаторе есть метод с именем IsEnumToDecimalConversion, который обрабатывает особый случай преобразования nullable enum в nullable decimal; довольно сложный особый случай.

Скорее всего, я не учел, что какой-то случай идет другим путем, и в результате сгенерировал плохой код. Спасибо за примечание; Я отправлю это в команду тестирования, и мы посмотрим, сможем ли мы запустить репро. Хорошие шансы, что если это окажется истинной ошибкой, это не будет исправлено в первоначальном выпуске C # 4; на данный момент мы принимаем только ошибки «пользователь убит током компилятором», чтобы релиз был стабильным.

3 голосов
/ 09 ноября 2009

Пока нет реального ответа, я изучаю, но первая строка составлена ​​так:

Func<decimal, ConsoleColor> converter1 = x => (ConsoleColor)(int)x;

Если вы попытаетесь создать выражение из предыдущей лямбды, оно будет работать.

РЕДАКТИРОВАТЬ: В спецификации C #, §6.2.2, вы можете прочитать:

явное преобразование перечисления между двумя типами обрабатывается лечение любого участвующего типа enum как основной тип этого enum-type, а затем выполняя неявный или явный числовой преобразование между полученным типы. Например, учитывая тип enum E с и базовый тип int, а выполняется преобразование из E в байт как явное числовое преобразование (§6.2.1) от int к байту и преобразование из байта в E обрабатывается как неявное преобразование чисел (§6.1.2) из ​​байта в int.

Таким образом, явные приведения из enum в decimal обрабатываются специально, поэтому вы получаете вложенные приведения (int, затем десятичные). Но я не понимаю, почему компилятор не разбирает лямбда-тело одинаково в обоих случаях.

...