2017-05-15 44 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(???); 

我想以某種方式使用fooFilter查詢fooList,並填寫filteredFooList

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

編輯:

我想簡短使問題更加清晰,但我可能留下了重要的信息。在我的實際程序中,List<Foo>是一個來自數據庫的大型結果(超過40k條目)。我試圖製作一個控制器方法(MVC),它可以採用任何與實體框架對象的字段名稱相匹配的參數組合。所以<Foo>是EF記錄類型。所以我想,以避免明確列出所有可以在控制器中過濾的(15個左右)字段:

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) 
    { 

    } 
} 

也許這是不可能的或一個好主意?

+0

你的fooFilter不是一個過濾器,它是一個Foo對象。過濾器謂詞是一個表達式,其值爲true或false,對嗎? – elgonzo

+1

'.ID'和'.Location'不能爲null,因爲它們是值類型。你打算如何處理值類型? – NetMage

+0

確實,'fooFilter'是一個考試程序,用於通過示例進行查詢,例如System.DirectoryServices.AccountManagement.PrincipalSearcher如何工作。 – NetMage

回答

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實際上可爲空的,就像你的榜樣暗示。

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

In我的情況,'列表'實際上是一個很大的數據庫列表(成千上萬)。這仍然適合嗎? – AnalogWeapon

+0

是的絕對,甚至更好,因爲您可以構建查詢並在服務器上運行,而不是將所有內容都列爲列表,然後_過濾。一般來說,您應該儘可能將其構造爲在服務器上運行。 –

0

假設你可以改變你的價值類型爲可以爲空:

class Foo { 
    public int? ID; 
    public string Description; 
    public long? 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); 
    } 
} 

要做到這一點:

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

如果你想一些真正通用的東西(例如,不需要知道字段名稱),您需要進入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

你可能想提一下,在這種情況下,還應該*實現'Equals(object)'方法,以避免在調用Foo.Equals((object)OtherFoo)時產生意外結果等。 –

0

通過看你的預期輸出,它似乎您要過濾fooList,以便您獲取與您的fooFilter對象具有相同Location的所有項目。如果這是你在問什麼,你可以這樣做:

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

我最近通過基於使用.NET主要Expression類輸入對象的動態建立的拉姆達查詢解決了一個非常類似的問題。如果你對你的案例感興趣,我可以寫出一個解決方案,只是謹慎地這樣做,因爲已經有一個答案被接受,但指出了潛在的選擇。

相關問題