2012-07-13 8 views
8

類似:その1のConvert a string to Linq.Expressions or use a string as Selector?文字列をlinq式に変換する方法は?

同様の1:Passing a Linq expression as a string?

同じ答えを持つもう一つの問題:

受け入れ:非常に多くの類似の質問を持っている何かを尋ねるためHow to create dynamic lambda based Linq expression from a string in C#?

理由これらの似たような質問の回答は、4年前(スコット・グーがコードマスターによって書かれたもの)から古い図書館(.net 3.5)用に書かれた図書館を参照していて、回答としてリンク以外の何かを取り除く。

ライブラリ内全体を含めることなくコードでこれを行う方法があります。これは、このような

query = "x => x.id == somevalue"; 

として式に文字列全体を回すために見ていないですが、代わりにのみ使用しようとしていること

public static void getDynamic<T>(int startingId) where T : class 
    { 
     string classType = typeof(T).ToString(); 
     string classTypeId = classType + "Id"; 
     using (var repo = new Repository<T>()) 
     { 
      Build<T>(
      repo.getList(), 
      b => b.classTypeId //doesn't compile, this is the heart of the issue 
       //How can a string be used in this fashion to access a property in b? 
      ) 
     } 
    } 

    public void Build<T>(
     List<T> items, 
     Func<T, int> value) where T : class 
    { 
     var Values = new List<Item>(); 
     Values = items.Select(f => new Item() 
     { 
      Id = value(f) 
     }).ToList(); 
    } 

    public class Item 
    { 
    public int Id { get; set; } 
    } 

注:ここでは

は、このような状況のためにいくつかのサンプルコードですアクセスとしての文字列

query = x => x.STRING; 
+0

は、あなたがする簡単な反射をやっ除外がありますあなたの 'Func'を作る? –

+0

@PaulPhillips - Reflectionは、渡されるクラスTのプロパティのプロパティタイプまたは名前を生成します。クラスTは、Entity Frameworkリポジトリへの接続時にタイプの参照としてのみ渡されます。すべてのクラスTのリストがリポジトリから返されます( 'repo.getList()')。 Linq式のクラスTのプロパティを含めることにリフレクションがどのように役立つでしょうか? –

+0

あなたの例では、linq-to-objectを実行しているように見えます。この場合、プロパティの値を反射的に取得できます。しかし、あなたが別の文脈で働いているので、私はそれがうまくいくかどうかはわかりません。私はあなたがチェックできるように私の試行を投稿しました –

答えて

15

ここで式ツリーの試みです:が、あなたのようなものを使用することができます。私はこれがEntityフレームワークで動作するかどうかまだ分かりませんが、試してみる価値があると思います。

Func<T, int> MakeGetter<T>(string propertyName) 
{ 
    ParameterExpression input = Expression.Parameter(typeof(T)); 

    var expr = Expression.Property(input, typeof(T).GetProperty(propertyName)); 

    return Expression.Lambda<Func<T, int>>(expr, input).Compile(); 
} 

はこのようにそれを呼び出します。

Build<T>(repo.getList(), MakeGetter<T>(classTypeId)) 

あなただけのFuncの代わりにExpression<Func<T,int>>を使用することができた場合は、単にCompileに呼び出しを削除(およびMakeGetterの署名を変更します)。


編集:コメントで 、TravisJは、彼がこのように使用できるか尋ねた:w => "text" + w.classTypeId

あり、これを行うには、いくつかの方法がありますが、読みやすくするために、私は最初にローカル変数を導入し推薦します、

var getId = MakeGetter<T>(classTypeId); 

return w => "text" + getId(w); 

主なポイントは、ゲッターは単なる関数であり、通常と同じように使用できるということです。このようなFunc<T,int>を読む:ここint DoSomething(T instance)

+0

linqPadでこれを動作させることができました - ここにコードがありますhttps://gist.github.com/3108507 – Hogan

+0

@Paul - いくつかの作業コードと例をありがとうございます。私もこれを動作させることができました。私はそれが行の下でより多くのlinqを妨害したので、署名を変更しなかった。私は1つの質問がありました。このように 'MakeGetter'を使うためにはどうすればいいでしょう:' w => "text" + MakeGetter (classTypeId) '? 'w =>" text "+ w.classTypeId'と同様です。 –

+0

@TravisJ私の編集を参照 –

1

私はこれを試していないし、動作するかどうかもわからない

b => b.GetType().GetProperty(classTypeId).GetValue(b, null);

+0

これは面白そうで、少なくともコンパイルされています。まだ多くのテストが必要です。 –

2

は私のテストコード(linqPad)とのあなたのための拡張メソッドです:

class test 
{ 
    public string sam { get; set; } 
    public string notsam {get; set; } 
} 

void Main() 
{ 
    var z = new test { sam = "sam", notsam = "alex" }; 

    z.Dump(); 

    z.GetPropertyByString("notsam").Dump(); 

    z.SetPropertyByString("sam","john"); 

    z.Dump(); 
} 

static class Nice 
{ 
    public static void SetPropertyByString(this object x, string p,object value) 
    { 
    x.GetType().GetProperty(p).SetValue(x,value,null); 
    } 

    public static object GetPropertyByString(this object x,string p) 
    { 
    return x.GetType().GetProperty(p).GetValue(x,null); 
    } 
} 

結果:

results

+0

これはあなたの例では機能しますが、ここではlinqとの統合はありません。 linqの統合についてのPaulの答えを見てください。 –

+0

私は、タイプ鉱山での彼の作品は、オブジェクト上で動作すると思います... 6。私はテンプレートが必要ないので、私はもっと穿孔されるだろうと思う。 – Hogan

関連する問題