2009-11-09 17 views
10

は、多くの行動のC#の仕様に近くなければなりませんExpressionTreesコンパイラのように見えますが、C#のとは異なり、任意のenum-typedecimalからの変換はサポートされていません。これはExpressionTreesのバグですか? #2

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では動作しません。これはバグですか?

まだ

答えて

16

おそらくバグで、おそらく私のせいです。申し訳ありません。

の10進数の変換は、実際にはランタイムでユーザー定義の変換として実装されていますが、組み込みの変換として扱われるため、コンパイラとランタイムに正しい式ツリーコードを作成するのが最も難しい部分の1つでした。コンパイラによって。 Decimalはこのプロパティを持つ唯一のタイプなので、これらのケースではアナライザにはあらゆる種類の専用ギアがあります。実際には、nullable enum to nullable decimal conversionの特殊ケースを処理するために、アナライザにIsEnumToDecimalConversionというメソッドがあります。非常に複雑な特殊なケース。

私は、他の方法をとっていくつかのケースを検討することができず、結果として悪いコードを生成したことは間違いありません。メモをありがとう。私はこれをテストチームに送りますが、私たちは再挑戦を受けることができるかどうかを見ていきます。これが真実のバグであると判明した場合、これはC#4の初期リリースでは修正されません。この時点では、リリースが安定するように、「ユーザーはコンパイラによって感電する」バグだけを取っています。

+0

私は人間がC#言語の作成に傷ついたことは知らなかった:) –

+0

"十進数変換は実際にはランタイムではユーザー定義の変換として実装されているが、コンパイラによる組み込み変換として扱われる"なぜこのようにしたのですか? – Brian

+2

@Brian:表記を変える変換、つまりintをdoubleにすると、まさにその変換を行うIL命令があります。十進数を2倍にすると、実際に変換を行うメソッドを呼び出すコードが生成されます。小数点のための組み込みCLR変換命令はありません。しかし、*言語*の観点からは、10進変換が*組み込みの言語変換であるように見えます。ビルトインとユーザー提供のコンバージョンのルールが異なります。だから、シーンの裏に何が起こっているのかを小数点で隠すために、特別な景色を構築しなければなりません。 –

3

ない本当の答え、私が調査んだけど、最初の行は次のようにコンパイルされている:あなたは以前、ラムダから式を作成しようとすると、それが動作します

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

EDIT:2種類の明示的な列挙変換 はの基本的な型として任意の参加列挙型 を処理する によって処理される

:C#の仕様では、§6.2.2、あなたが読むことができますその のenum-typeを入力し、 の型の間で の暗黙的または明示的な数値 の変換を実行します。たとえば、int型のenum型 Eを指定すると、 からEへの変換は、 (§6.2.1)の明示的な数値変換として として処理され、 バイトから変換されます〜Eは、 を暗黙の数値変換として処理します。 (§6.1.2)からbyteまでです。

enumからdecimalへの明示的なキャストが特に処理されるため、ネストされたキャスト(intから10進)を取得するのはこのためです。しかし、コンパイラがラムダ本体を同じ方法で解析しない理由は、どちらの場合でもわかりません。

+2

コンパイラはおそらく別のパスでネストされたキャストを発行します。この場合、実行時に失敗するConvertノードが作成されます。ネストされたコンバージョンを生成するコンパイラのバグか、10進数から変換の列挙型を理解するExpression APIのバグかは、読者に任せられます。私は、適切な変換ノードを発行するのはcscの責任だと思っています。 –

+0

私は同意します。実際には、 "expr = lambda"行でコンパイルエラーが発生します。したがって、コンパイラは、イベントを追加の変換ノードやその他のものを実際に放出しようとはしません。ラムダ本体が無効であると見なしますが、これはc#specによると無効です。 –

+0

'double - > enum-type'変換の場合、cscは' double - > int'を直接出力せず、 'double - > enum-type 'をそのまま使用し、ExpressionTreesコンパイラはこの細かいことを理解しています... – ControlFlow

関連する問題