2011-11-08 3 views
9

Expression<Func<T, object>>インスタンスを受け入れるメソッドがあります。私は実際 のデータ型がobjectではなく特定の式インスタンスによって返されるようにしたいと考えています。式から実際の戻り値の型を取得する<Func <T, object>>インスタンス

私は直接プロパティの参照のために働くことができますので、式x => x.IntegerPropertyを渡すと、整数の型参照を取得できます。このアプローチでは、それをMemberExpressionに変換する必要があります。

しかし、私はそれを任意の表現のために働かせることはできません。たとえば、式がx => x.IntegerProperty.ToString()の場合、文字列の型参照を取得したいとします。私はこれをMemberExpressionにコンパイルすることはできません。もし私がただ.Compile()と返された型をチェックすれば、私は "object"を取得します。

特定の式のインスタンスを見て、実際の戻り値の型を取得するにはどうすればよいですか?

+0

技術的には、式の実際の戻り値の型は、「オブジェクト」です。関数は 'object'を返す必要があったので、返される型(この場合は変換)であることを保証するために必要な式が生成されました。 –

答えて

17

このようなことが、このトリックを行う可能性があります。それはおそらくすべての可能性をカバーしているわけではありませんが、それは始まりです。

public static Type GetObjectType<T>(Expression<Func<T, object>> expr) 
{ 
    if ((expr.Body.NodeType == ExpressionType.Convert) || 
     (expr.Body.NodeType == ExpressionType.ConvertChecked)) 
    { 
     var unary = expr.Body as UnaryExpression; 
     if (unary != null) 
      return unary.Operand.Type; 
    } 
    return expr.Body.Type; 
} 
+0

これは、実際には 'object'ではない場合、他の表現型を考えることができませんでした。私が考えることができるすべてのケースをカバーします。 –

+0

うまく働いた。私はかなり特定の状況でこれを使用しているので、あなたがカバーしていないエッジケースがない場合、彼らはまだ私に痛みを引き起こしていません。ありがとう! –

+0

expr.Body.Typeで十分ではありませんか?上記のコードを使用すると、例えばi =>(float)iのiを整数として使用すると間違った結果になります。その後、このコードは整数を返し、浮動小数点は返しません。しかし、単にexpr.Body.Typeが機能します。 –

2

これは不可能ではありませんが、これは特に困難です。それは、表現木を歩いて潜在的に複雑な論理を行う必要があります。たとえば、次の式を渡した場合、あなたは何を見たいと思いますか?

Func<bool, object> expr = switch => switch ? 1 : "False"; 

この方法は可能性intまたはstringを返すのいずれか。

ここで、このロジックの一部をコンパイラでオフロードすることで、より多くの進歩を遂げることができます。メソッドのパラメーターをFunc<T, object>からFunc<T, TReturn>に変更し、メソッド内でtypeof(TReturn)を使用して、コンパイラーが式の戻りタイプを決定したものを判別することができます。

もちろん、私の例の場合、あなたはまだobjectに対して作業しています。しかし、x => x.IntegerProperty.ToString()の例では、あなたが探しているものがstringになります。

+0

あなたはいくつかの良い点を挙げていますが、これは、そのようなエッジケースが起こらないような特定の状況で使用されています(または、それらについて知ることで簡単に回避できます)。ありがとう! –

+2

実際には@Adam Marasの場合、三項演算子は「int型とstring型の間の暗黙の変換がないため、条件式の型を判別できません」というコンパイル時エラーが発生するため、コンパイルされません。 –

+0

文字通りのコードサンプルよりも多くの考えがありました。 –

0

生意気な方法(と、それは実際にFuncを呼び出すことを伴う)のビットに、しかし、あなたはこれを行うことができます:それはすべての状況で動作する保証はないです

using System; 

class Program 
{ 
    static Func<T,object> MakeFunc<T>() 
    { 
     return x => 23; 
    } 

    static Type GetReturnType<T>(Func<T,object> f) 
    { 
     return f(default(T)).GetType(); 
    } 

    static void Main(string[] args) 
    { 
     Type t = GetReturnType(MakeFunc<string>()); 
     Console.WriteLine(t); 
    } 
} 

、私は追加する必要があります - 特にdefault(T) ISN場合Funcの有効なパラメータです。しかし、少なくともそれは潜在的な出発点です。

+2

戻り値の型を取得するために式を実行することについてどう思いますか。関数に副作用がある場合はどうなりますか?私の特定のケースではそれは大きな心配ではありませんが、私はちょうどうまくいくと思われ、実行を必要としない答えを受け入れました。しかし、ありがとう! –

+0

@セス:私は個人的に表現を実行することについてあまり喜んでいないでしょう(それはアプローチの限界です) - 私は頭の上から出てくることができた最高のものでした。このアプローチの利点の1つは、 'Expression'インスタンスではなく' Func'インスタンスで動作することです。 –

関連する問題