Roslyn で Expression に含まれる Enum の値が取れなくなったと思ったらバグだった
例えば、以下のコードを VS2013 で動かすと最終的に NumberEnum.One
という定数から "1" という値が取れます。
class Hoge { public NumberEnum NumberEnum { get; set; } } enum NumberEnum { Zero, One } static void Main(string[] args) { Expression<Func<Hoge, bool>> expression = _ => _.NumberEnum == NumberEnum.One; var bin = (BinaryExpression) expression.Body; var r = bin.Right; var c = r as ConstantExpression; var value = c.Value; Console.WriteLine("value: " + value); // "value: 1" }
ところが、これと同じコードを VS2015 で動かすと、var c = r as ConstantExpression;
でキャストに失敗して次の行でヌルポになります。
r の型が変わってしまっているわけですが、ちょっとデバッガで見てみましょう。
NodeType
プロパティの値が "Convert" になっていますね。VS2013 ではここは "Constant" でした。
Roslyn で仕様変更があったのかと思って調べてみたんですが、そうではなくどうやら普通にバグだったようです。既にプルリクエストも出ており、マージ済みでした。
issue
github.com
github.com
pull request
github.com
例であげたコードで言うと、
Expression<Func<Hoge, bool>> expression = _ => _.NumberEnum == NumberEnum.One;
から取れる Body の値が変わってしまっているわけですね。比較するとこうなります。
VS2013: (Convert(_.NumberEnum) == 1) VS2015: (Convert(_.NumberEnum) == Convert(One))
Roslyn は現在 v1.1 の開発が進んでいるようですが、そちらに含まれることになるんでしょう。
対策
まぁそれはそれで待つとして、とりあえず今どうするかなんですが、色々こねくり回した結果どうしても "1" は取れず "One" という値しか取れないのでこうなりました。
Expression<Func<Hoge, bool>> expression = _ => _.NumberEnum == NumberEnum.One; var bin = (BinaryExpression)expression.Body; var r = bin.Right; // var c = r as ConstantExpression; // var value = c.Value; var u = r as UnaryExpression; var c = u.Operand as ConstantExpression; var value = (int) ((NumberEnum) c.Value); Console.WriteLine("value: " + value); // "value: 1"
うわぁこれはひどい。。。どうにかならないですかね。