2016-08-24 45 views
4

可以創建一個通用搜索方法,其中密鑰是未知的;例如,列表鍵將被傳遞給參數,並執行類似的搜索並返回過濾的列表。有可能創建一個通用搜索方法,其中密鑰是未知

代碼應該是這樣的:

public List<T> LikeSearch<T>(List<T> AllData,T key, string searchString) 
{ 
    List<T> _list = new List<T>(); 
    //Perform the search on AllData based on searchString passed on the key 
    //given 
return _list; 
} 

用途將是這樣的:

例1

List<Users> _users = LikeSearch<Users>(AllUsers,'Name','sam'); 

AllUsers是100 users列表。

實施例2

List<Customers> _cust = LikeSearch<Customers>(AllCustomers,'City','London'); 

AllCustomers哪裏是100 Customers列表。

請sugest

+0

爲什麼'key'類型'T '?它似乎是一個屬性名稱,它不應該總是一個「字符串」?這可以通過反射來解決。它會很慢... – InBetween

+0

是的,正確的抱歉....鍵將始終在這裏字符串... –

+0

看看[動態LINQ](http://weblogs.asp.net/scottgu/動態LINQ部分-1-使用最LINQ的動態查詢的庫)。 –

回答

2

假設key始終是指任何類型的T是實現公共財產,你可以做到以下幾點:

public static List<T> LikeSearch<T>(this List<T> data, string key, string searchString) 
{ 
    var property = typeof(T).GetProperty(key, BindingFlags.Public | BindingFlags.GetProperty | BindingFlags.Instance); 

    if (property == null) 
     throw new ArgumentException($"'{typeof(T).Name}' does not implement a public get property named '{key}'."); 

    //Equals 
    return data.Where(d => property.GetValue(d).Equals(searchString)).ToList(); 

    //Contains: 
    return data.Where(d => ((string)property.GetValue(d)).Contains(searchString)).ToList(); 
} 
+0

謝謝InBetween .....爲我工作!你拯救了我的一天。 –

+0

@AbhinawKaushik不客氣,總是樂於提供幫助。我已經修復了一些代碼,請確保使用最新的編輯。 – InBetween

+0

再次感謝@InBetween我已經更改爲包含我的用途。非常感謝。 –

3

我認爲this link會幫助你...問題是不同的,但你可以找到答案。對於參考我又在這裏張貼的答案...

using System; 
using System.Collections.Generic; 
using System.Linq; 
using System.Text.RegularExpressions; 
using System.Linq.Expressions; 
using System.Reflection; 
namespace Rextester 
{ 
    public class Program 
    { 
     public static void Main(string[] args) 
     { 

      List<Demo> all= new List<Demo>(); 
      all.Add(new Demo{Name="a"}); 
      all.Add(new Demo{Name="ab"}); 
      all.Add(new Demo{Name="abc"}); 
      all.Add(new Demo{Name="cba"}); 
      all.Add(new Demo{Name="bac"}); 
      all.Add(new Demo{Name="ddd"}); 

      var t= Filter(all,"Name","a"); 

      Console.WriteLine(t.Count); 
     } 

     public static List<T> Filter<T>(List<T> Filterable, string PropertyName, object ParameterValue) 
     { 
      ConstantExpression c = Expression.Constant(ParameterValue); 
      ParameterExpression p = Expression.Parameter(typeof(T), "xx"); 
      MemberExpression m = Expression.PropertyOrField(p, PropertyName); 

      MethodInfo method = typeof(string).GetMethod("Contains", new[] { typeof(string) }); 

      var containsMethodExp = Expression.Call(m, method, c); 
      var Lambda= Expression.Lambda<Func<T, bool>>(containsMethodExp, p);   

      //var Lambda = Expression.Lambda<Func<T, Boolean>>(Expression.Equal(c, m), new[] { p }); 

      Func<T, Boolean> func = Lambda.Compile(); 
      return Filterable.Where(func).ToList(); 
     } 
    } 

    public class Demo 
    { 
     public string Name{get;set;} 
    } 
} 
+0

Moumit ...感謝您的幫助,這是一個Equals場景,我一直在尋找包含搜索。如果可能的話,我想我需要使用Expression.Equals來獲取Expression.Contains。反正非常感謝你。 –

+0

@AbhinawKaushik ...這與你將要使用哪種解決方案無關...使用'ExpressionTree'你也可以實現這個.. – Moumit

+0

感謝@Moumit這個工作! –

0

與LINQ方法Where

list.Where(x => x.YourKey.Contains(searchString)) 

實施例1

List<Users> _users = AllUsers.Where(x => x.Name.Contains("sam")); 

例2

List<Customers> _cust = AllCustomers.Where(x => x.City.Contains("London")); 

你可以這樣寫,否則的方法:

public List<T> LikeSearch<T>(List<T> list, Func<T, string> getKey, string searchString) 
{ 
    return list.Where(x => getKey(x).Contains(searchString)).ToList(); 
} 

而且你可以使用它像這樣:

例1

List<Users> _users = LikeSearch(AllUsers, x => x.Name, "sam"); 

例2

List<Customers> _cust = LikeSearch(AllCustomers, x => x.City, "London"); 

編輯:下面關於解決方案的小基準這裏提出

我只爲基準的Contains版本大家。

有了這個,我們可以看到(根據您的計算機和星星......上):

其間OneProperty:00:00:00.0026050

Moumit OneProperty:00:00:00.0013360

Mine OneProperty:00:00:00。0010390

兩個不同類別來這裏是爲了測試是否屬性的數目改變的東西

其間LotProperties:00:00:00.0026378

Moumit LotProperties:00:00:00.0012155

礦區性質:00:00:00.0010021

我很驚訝Moumit的解決方案是如何快速的,我預計它在運行時編譯會更慢。但是,儘管如此,我們可以看到GetPropertyGetValue確實很慢。

基準代碼:

static void Main(string[] args) 
    { 
     int size = 10000; 
     Dictionary<string, List<long>> time = new Dictionary<string, List<long>>() 
     { 
      {"InBetween OneProperty", new List<long>() }, 
      {"Moumit OneProperty", new List<long>() }, 
      {"Mine OneProperty", new List<long>() }, 
      {"InBetween LotProperties", new List<long>() }, 
      {"Moumit LotProperties", new List<long>() }, 
      {"Mine LotProperties", new List<long>() }, 
     }; 
     List<OneProperty> oneProperties = new List<OneProperty>(); 
     List<LotProperties> lotProperties = new List<LotProperties>(); 
     for (int i = 0; i < size; ++i) 
     { 
      oneProperties.Add(new OneProperty() { Key = i.ToString() }); 
      lotProperties.Add(new LotProperties() { Key = i.ToString() }); 
     } 
     Stopwatch sw = new Stopwatch(); 
     for (int i = 0; i < 1000; ++i) 
     { 
      sw.Start(); 
      InBetween.LikeSearch(oneProperties, "Key", "999"); 
      sw.Stop(); 
      time["InBetween OneProperty"].Add(sw.Elapsed.Ticks); 
      sw.Reset(); 
      sw.Start(); 
      Moumit.Filter(oneProperties, "Key", "999"); 
      sw.Stop(); 
      time["Moumit OneProperty"].Add(sw.Elapsed.Ticks); 
      sw.Reset(); 
      sw.Start(); 
      Mine.LikeSearch(oneProperties, x => x.Key, "999"); 
      sw.Stop(); 
      time["Mine OneProperty"].Add(sw.Elapsed.Ticks); 
      sw.Reset(); 

      sw.Start(); 
      InBetween.LikeSearch(lotProperties, "Key", "999"); 
      sw.Stop(); 
      time["InBetween LotProperties"].Add(sw.Elapsed.Ticks); 
      sw.Reset(); 
      sw.Start(); 
      Moumit.Filter(lotProperties, "Key", "999"); 
      sw.Stop(); 
      time["Moumit LotProperties"].Add(sw.Elapsed.Ticks); 
      sw.Reset(); 
      sw.Start(); 
      Mine.LikeSearch(lotProperties, x => x.Key, "999"); 
      sw.Stop(); 
      time["Mine LotProperties"].Add(sw.Elapsed.Ticks); 
      sw.Reset(); 
     } 
     foreach (string key in time.Keys) 
      Console.WriteLine($"{key}: {new TimeSpan((long)time[key].Average())}"); 
     Console.ReadKey(); 
    } 

    class OneProperty 
    { 
     public string Key { get; set; } 
    } 
    class LotProperties 
    { 
     public string A { get; set; } 
     public string B { get; set; } 
     public string C { get; set; } 
     public string D { get; set; } 
     public string E { get; set; } 
     public string F { get; set; } 
     public string G { get; set; } 
     public string H { get; set; } 
     public string I { get; set; } 
     public string J { get; set; } 
     public string K { get; set; } 
     public string L { get; set; } 
     public string M { get; set; } 
     public string N { get; set; } 
     public string O { get; set; } 
     public string P { get; set; } 
     public string Q { get; set; } 
     public string R { get; set; } 
     public string S { get; set; } 
     public string T { get; set; } 
     public string U { get; set; } 
     public string V { get; set; } 
     public string W { get; set; } 
     public string X { get; set; } 
     public string Y { get; set; } 
     public string Z { get; set; } 
     public string Key { get; set; } 
    } 
+0

OP只知道'City'的名字,他不能直接調用該屬性。 – InBetween

+0

你從哪裏讀到的?他說屬性是未知的,也許是因爲這個名字可以改變,但他知道這個名字,否則他如何寫出關鍵字符串?如果他不知道,你的解決方案仍然和我一樣。 –

+0

來自問題中的用法示例和註釋。我沒有跟着你解決我的問題。我使用反射來查找具有給定名稱的財產。 – InBetween

相關問題