Func<T> から Expression<Func<T>> のインスタンスを生成する方法


次のような関数を作ろうとしています。

[code]

    public static void Hoge<int>(Func<int> function)
    {
        var value = function();
        var expression = new Expression<Func<int>>(function);  // ←ビルドエラー。何か方法は無いか？
        var name = (expression.Body as MemberExpression).Member.Name;
    
        // 以下、valueとnameを使った処理
    }
    
[/code]

`Hoge(() => x)` という感じに呼び出して、変数名`x`とその値を同時に渡したいのです。  
しかし、このような`Expression<T>`のコンストラクタは存在しないので、このままでは実現できません。  
`Hoge()`の引数を`Expression<Func<int>>`にして、`Compile()`してから実行して値を取り出す、というのも可能ですが、`Compile()`がとても遅いのでやりたくないです。  
※`MemberExpression`経由で変数名を取り出すのに比べて2桁以上遅い

↓こういう形ならさくっと`Expression`インスタンスを作れるから簡単だろうと思いましたが、もしかしてこれはコンパイル時にすごいことをやってくれているだけなのであって、実行時にやろうとすると容易ではないのでしょうか？

[code]

    int x = 10;
    Expression<Func<int>> exp = () => x;
    
[/code]




`Func<T>` は実行可能なコードへの参照、`Expression` は構文木のようなデータ構造ですから、`Func<T> → Expression`
の変換は逆コンパイルをするようなものです。

`Expression<T> e = ラムダ式;` は「`Expression`
を生成するプログラム」に変換される糖衣構文のようなものですが、コンパイル中には当然その部分の構文木もあるわけなので、これを `Expression`
に変形するのも容易でしょう。

ラムダ式をデリゲートと式木（あるいは文字列）の両方にコンパイルできると便利そうですが、実装される気はしないですね・・・。

[code]

    // 妄想：後から変換できるように
    Lambda<Func<int>> l = () => 1; //この型はコンパイル時のみ存在する？？
    Func<int> f = l;
    Expression<Func<int>> e = l; //式木にできないラムダ式はどうする？
    
    // 妄想：同時に受け取る
    Func<int> f, Expression<Func<int>> e;
    (f, e) = () => 1; //この構文はC#にはない
    
[/code]

参考

  * [c# - converting a .net `Func<T>` to a .net `Expression<Func<T>>` - Stack Overflow](https://stackoverflow.com/q/767733/2818869)
  * [式木（Expression Trees） (C# によるプログラミング入門)](http://ufcpp.net/study/csharp/sp3_expression.html)
  * [Expression(TDelegate) クラス (System.Linq.Expressions)](https://msdn.microsoft.com/ja-jp/library/bb335710.aspx)

* * *

追記：質問にあるコードでは `() => hoge.piyo`
といった式を期待されているようですが、単純なフィールド・プロパティアクセスならリフレクションを使うと速いかもしれません。

[c# - How do I get the value of MemberInfo? - Stack
Overflow](https://stackoverflow.com/q/238555/2818869)




`Func<T>` は実行可能なコードへの参照、`Expression` は構文木のようなデータ構造ですから、`Func<T> → Expression`
の変換は逆コンパイルをするようなものです。

`Expression<T> e = ラムダ式;` は「`Expression`
を生成するプログラム」に変換される糖衣構文のようなものですが、コンパイル中には当然その部分の構文木もあるわけなので、これを `Expression`
に変形するのも容易でしょう。

ラムダ式をデリゲートと式木（あるいは文字列）の両方にコンパイルできると便利そうですが、実装される気はしないですね・・・。

[code]

    // 妄想：後から変換できるように
    Lambda<Func<int>> l = () => 1; //この型はコンパイル時のみ存在する？？
    Func<int> f = l;
    Expression<Func<int>> e = l; //式木にできないラムダ式はどうする？
    
    // 妄想：同時に受け取る
    Func<int> f, Expression<Func<int>> e;
    (f, e) = () => 1; //この構文はC#にはない
    
[/code]

参考

  * [c# - converting a .net `Func<T>` to a .net `Expression<Func<T>>` - Stack Overflow](https://stackoverflow.com/q/767733/2818869)
  * [式木（Expression Trees） (C# によるプログラミング入門)](http://ufcpp.net/study/csharp/sp3_expression.html)
  * [Expression(TDelegate) クラス (System.Linq.Expressions)](https://msdn.microsoft.com/ja-jp/library/bb335710.aspx)

* * *

追記：質問にあるコードでは `() => hoge.piyo`
といった式を期待されているようですが、単純なフィールド・プロパティアクセスならリフレクションを使うと速いかもしれません。

[c# - How do I get the value of MemberInfo? - Stack
Overflow](https://stackoverflow.com/q/238555/2818869)

