2016-07-14 10 views
2

"Id"プロパティ、時には "Description"プロパティで何度かフィルタリングしたいと思います。プロパティ名(filterColumn)とプロパティ値(filterValue)を両方とも文字列として渡したいだけです。C#LinqフィルタIEnumerableの動的プロパティと値

私は次のことを試してみました:

IEnumerable<Sample> result = sampleList.Where(x => x.GetType().GetProperty(filterColumn).Name == filterValue); 

string whereQuery = string.Format(" {0} = \"{1}\"", filterColumn, filterValue); 
IEnumerable<Sample> result = sampleList.AsQueryable().Where(whereQuery); 

目のオプションは、私は、 "説明" としてfilterColumnを渡した場合、動作しますが、文字列と整数の間incomptable '=' 演算子を投げます「Id」がfilterColumnとして渡され、いくつかのfilterValueが「1」のようなときにエラーが発生します。

ありがとうございました。ありがとう

+0

最初に、*プロパティ名*が指定されたプロパティ値と同じであることを確認しています。 PropertyInfoで '.GetValue(x、null)'を呼び出す必要があります...'=='ではなく 'Equals'を使いたいとします。 –

+0

なぜあなたは '.AsQueryable()'をやっていますか? – Enigmativity

答えて

1

あなたの最初のアプローチが動作します。 Jon Skeetのコメントを拡大して、ここで調整されたステートメントです。

IEnumerable<Sample> result = sampleList.Where(
    x => x.GetType().GetProperty(filterColumn).GetValue(x, null).Equals(filterValue) 
); 

これを少しコンテキストにするには、異なるデータ型を許可する必要があります。少なくとも2つの方法でこれを行うことができます。一般的な方法を使用するか、オブジェクトデータ型を使用します。説明のために、私はオブジェクトアプローチを使用します。プロパティ値は、あなたが渡している同じデータ・タイプのものであろうことを保証するためにチェックを全くタイプが存在しないよう

public IEnumerable<Sample> GetFiltered(
    IEnumerable<Sample> samples, string filtercolumn, object filtervalue 
{ 
    return samples.Where(
     x => x.GetType().GetProperty(filtercolumn).GetValue(x, null).Equals(filtervalue) 
    ); 
} 

IEnumberable<Sample> sampleList; 

var byId = GetFiltered(sampleList, "Id", 100); 
var byDescription = GetFiltered(sampleList, "Description", "Some Value"); 

この例では、本当に安全ではありません。たとえば、渡すからあなたを止めるものは何もありません「の説明"と100をパラメータとして使用します。整数と文字列の意味のある比較はできないので、空の結果が常に出てくるでしょう。 Equalsメソッドは例外をスローしません.2つのオブジェクトが異なることがわかります。 Jonが指摘したように、 "=="演算子ではなく、常にこの場合Equalsを使用したいと考えています。 Equalsメソッドはコンテンツを比較するためのもので、 "=="は参照を比較するものです。例:

Console.WriteLine(12 == 12); 
// True 

object a = 12; 
object b = 12; 

Console.WriteLine(a == b); 
// False - because, due to boxing, a and b are separate objects 
// that happen to contain the same value. (Check out "boxing" 
// if this doesn't make sense.) 

Console.WriteLine(a.Equals(b)); 
// True - because the Equals method compares content (value) 

また、 "=="演算子を使用する場合、文字列にはいくつかの特殊な動作があります。覚えておくべき重要なことは、参照(コンテナ)とコンテンツに違いがあることです。あなたは内容を比較したい、それは等しいことを意味します。 (私は、Visual Studioのイミディエイトウィンドウが "=="を使用しているときに文字列に関する結果に一貫性がないことに気づいた。

あなたは2番目のアプローチが有効であると述べています。私は標準のIEnumerable.Whereメソッドでこのタイプのフィルタ文字列を見ていません。だから私はあなたがいくつかの拡張機能を使っていると推測しています。あなたの例は、示されているように動作しません。 DataTableクラスは、使用方法に合ったフィルタ文字列を使用します。一般に、フィルタ文字列は、データ型に基づいて異なる方法で構築されなければならない。たとえば、文字列には引用符(必要なもの)が必要ですが、整数値には引用符は使用されません。

1

必要な操作で辞書を設定することもできます。

public IEnumerable<Sample> GetFiltered(
    IEnumerable<Sample> samples, string property, string value) 
{ 
    var map = new Dictionary<string, Func<string, Func<Sample, bool>>>() 
    { 
     { "Description", v => s => s.Description == v }, 
     { "Id", v => s => s.Id == int.Parse(v) }, 
    }; 
    return samples.Where(map[property](value)); 
} 

ここでの利点は、あなたがこのような値の範囲、または複数のプロパティを含むものでカスタムフィルタを追加するなど、より複雑な比較を行うことができるということです。