2017-05-15 8 views
0

タイプFooのオブジェクトのリストと、タイプFooのオブジェクトの別のインスタンスがあります。 linqを使用して、インスタンスのnull以外のプロパティに基づいてリストをフィルタリングしたいと思います。Linq:タイプAのオブジェクトに基づいたタイプAのフィルタリスト?

class Foo { 
    public int ID; 
    public string Description; 
    public long Location; 
} 

Foo fooFilter = new Foo() { 
    ID = null, 
    Description = null, 
    Location = 1 
} 

List<Foo> fooList = new List<Foo>(); 

fooList.Add(new Foo(){ID = 1, Description = "one", Location = 1}); 
fooList.Add(new Foo(){ID = 2, Description = "two", Location = 0}); 
fooList.Add(new Foo(){ID = 3, Description = "three", Location = 1}); 

List<Foo> filteredFooList = fooList.Where(???); 
私は何とか fooListを照会して filteredFooListを埋めるために fooFilterを使用したい

[ 
    {ID = 1, Description = "one", Location = 1}, 
    {ID = 3, Description = "three", Location = 1} 
] 

EDIT:

私が質問をより明確にするために簡単なことしようとしていた

が、私は重要な情報が残っているかもしれません。私の実際のプログラムでは、List<Foo>はデータベースからの大きな結果です(40k以上のエントリ)。私は、エンティティフレームワークオブジェクトのフィールド名に一致するパラメータの任意の組み合わせを取ることができるコントローラメソッド(MVC)を作成しようとしています。したがって<Foo>はEFレコードタイプです。

public class Home : Controller 
{ 
    public ActionResult FilteredFooList(int ID, string Description, long Location, etc, etc, etc) 
    { 

    } 
} 

そして、より多くのような何かを:

たぶん
public class Home : Controller 
{ 
    public ActionResult FilteredFooList(Foo filterObj) 
    { 

    } 
} 

このだから私は、明示的に、コントローラでのフィルタリングすることができ、すべての(15程度)のフィールドをリストアップすることを避けるためにしようとしています可能ではないか良いアイデアですか?

+0

fooFilterはフィルタではなく、Fooオブジェクトです。フィルタ述語とは、真か偽かを評価する式です。 – elgonzo

+1

'.ID'と' .Location'は値型なので 'null'にすることはできません。値の型をどのように扱う予定ですか? – NetMage

+0

真の 'fooFilter'は、' System.DirectoryServices.AccountManagement.PrincipalSearcher'がどのように動作するかのように、例文でクエリを実行するための、examplarです。 – NetMage

答えて

1

は、あなたのデータオブジェクトへの不必要なプロパティを追加することにより、コーナーに自分自身を塗らないでください、彼らは、データオブジェクトを滞在する必要があります。条件リストで条件付きでフィルターをかけたい動的な照会を効果的に構築しようとしています。これを行うパターンがあります。

基本クエリーから開始して、プロパティの1つでフィルタリングするかどうかを決定します。他のプロパティの他のプロパティと同じ操作を行います。あなたが最後に到達する頃には、結果だけを集めることができます。

var filter = new Foo 
{ 
    ID = null, 
    Description = null, 
    Location = 1, 
}; 

var data = new List<Foo> 
{ 
    new Foo { ID = 1, Description = "one", Location = 1 }, 
    new Foo { ID = 2, Description = "two", Location = 0 }, 
    new Foo { ID = 3, Description = "three", Location = 1 }, 
}; 

var query = data.AsEnumerable(); 
if (filter.ID != null) 
    query = query.Where(x => x.ID == filter.ID); 
if (filter.Description != null) 
    query = query.Where(x => x.Description == filter.Description); 
if (filter.Location != null) 
    query = query.Where(x => x.Location == filter.Location); 

var result = query.ToList(); 

これはIDLocationはあなたの例が示しているだけのように実際にNULL可能であることを前提としています。

public class Foo 
{ 
    public int? ID { get; set; } 
    public string Description { get; set; } 
    public long? Location { get; set; } 
} 
+0

In私の状況では、 'List 'は実際にはデータベースからかなり大きなリスト(何千も)です。これはまだそれにふさわしいでしょうか? – AnalogWeapon

+0

はい、すべてをリストとして取得するのではなく、サーバーでクエリを作成して実行することができますので、さらに優れています。一般的には、可能な限りサーバ上で実行するように常に構造化するようにしてください。 –

0

あなたがNULL可能であるためにあなたの値の種類を変更することができますと仮定:

class Foo { 
    public int? ID; 
    public string Description; 
    public long? Location; 
} 

その後、あなたには、いくつかの拡張機能を使用することができます:あなたが望んでいた場合は

var filteredFooList = fooList.Where(f => f.ID.EqualOrNull(fooFilter.ID) && f.Description.EqualOrNull(fooFilter.Description) && f.Location.EqualOrNull(fooFilter.Location)); 

:これを行うには

public static class Ext { 
    public static bool EqualOrNull<T>(this T? value, T? filter) where T : struct, IComparable { 
     return (filter == null) || (value.Value.CompareTo(filter.Value) == 0); 
    } 
    public static bool EqualOrNull<T>(this T value, T filter) where T : class, IComparable { 
     return (filter == null) || (value.CompareTo(filter) == 0); 
    } 
} 

をあなたがReflの世界に足を踏み入れる必要がある本当に一般的なもの(例えばフィールド名を知ることに依存しない) 。

2

インスタンス化されていないプロパティのみをフィルタ処理したい場合は、フィルタは必要ありません。

class Foo 
{ 
    public int ID; 
    public string Description; 
    public long Location; 

    public bool IsInstanciated() 
    { 
     return this.ID != default(int) && this.Description != default(string) && this.Location != default(long); 
    } 
} 

List<Foo> filteredFooList = fooList.Where(f => f.IsInstanciated()); 

編集: あなたが本当にフィルタとしてそのインスタンス化クラスを使用する必要がある場合、私は、あなたが期待される出力を見ることによってIEquatable<T>

class Foo : IEquatable<Foo> 
{ 
    public int ID; 
    public string Description; 
    public long Location; 

    public bool Equals(Foo other) 
    { 
     // Whatever your logic is 
     return string.IsNullOrEmpty(this.Description) == string.IsNullOrEmpty(other.Description) && 
       this.ID > 0 == other.ID > 0 && 
       this.Location > 0 == other.Location > 0; 
    } 
} 

public class Home : Controller 
{ 
    public ActionResult FilteredFooList(Foo filterObj) 
    { 
     List<Foo> filteredFooList = fooList.Where(f => f.Equals(filterObj)); 
    } 
} 
+1

'Foo.Equals((object)OtherFoo)'が呼び出されたときなど、意図しない結果を招かないように、この場合は 'Equals(object)'メソッドを実装する必要があります。 –

0

を使用することをお勧めしたいですfooListをフィルタリングして、同じLocationのアイテムをすべてfooFilterオブジェクトとして取得するように見えます。それはあなたが求めているものだ場合は、この操作を行うことができます。

List<Foo> filteredFooList = fooList.Where(item => item.Location == fooFilter.Location); 
0

私は最近、動的に.NETで主にExpressionクラスを使用して入力オブジェクトに基づいてラムダクエリを構築することにより、非常に同様の問題を解決しました。私はあなたの事例に興味があるならば解決策を書くことができます。すでに回答が受け入れられているが潜在的な選択肢を指摘しているので、これを行うには慎重であるだけです。

関連する問題