簡體   English   中英

如何在運行時將屬性放入linq表達式?

[英]How can I put a property to linq expression at runtime?

我需要通過字符串參數“ propertyName”將屬性名稱傳遞給“ GetClientsByFilter()”方法,並在LINQ表達式中使用此屬性。

假定需要使用反射。

您是否知道我必須在下面使用帶注釋“ // pseudo code”的字符串代替什么? 謝謝。

public class Client
{
    public string FirstName { get; set; }
    public string LastName { get; set; }
}

internal class DataLayer
{
  public static List<Client> GetClientsByFilter(string search, string propertyName)
  {
     //it's Entity Framework context
     using (var dbContext = new LibDbContext())
        {
            List<Client> clients;

                 clients = dbContext.Clients
                .Where(item => item.[propertyName].Contains(search)) // pseudo code
                .ToList();
        }
     return clients;
  }
}

您可以傳遞另一個獲取屬性值的lambda而不是屬性:

public static List<Client> GetClientsByFilter(string search, 
                                              Func<Client, string> propertyGetter)
{
  //it's Entity Framework context
  using (var dbContext = new LibDbContext())
  {
    List<Client> clients;

    clients = dbContext.Clients
                       .Where(item => propertyGetter(item).Contains(search))
                       .ToList();
  }
  return clients;
}

不幸的是,當您從“外部”獲取屬性名稱時,無法使用此方法,並且無法構建適當的lambda來獲取值。 在這種情況下,您可以為每個屬性名稱准備一個lambda字典。

如果要使用反射,請在此處查看答案

我已經解決了這樣的問題:

    public static List<Client> GetClientsByFilter(string search, string propertyName)
    {
        using (var dbContext = new LibDbContext())
        {     
            List<Client> clients;

              switch (propertyName)
              {
                case "LastName":

                  clients = dbContext.Clients
                      .Where(item => item.LastName.Contains(search))
                      .ToList();
                break;

                case "FirstName":

                  clients = dbContext.Clients
                      .Where(item => item.FirstName.Contains(search))
                      .ToList();
                break;
              }
           return clients;
        } 

但是我想重寫這段代碼,並且無需復制/粘貼即可使其更加清晰

這是一個幾乎重復的問題,“ 如何在C#中創建一個表達式樹來表示'String.Contains(“ term”)'?” Marc的答案提供了以下代碼來構建表達式,這就是您要查找的內容:

static Expression<Func<T, bool>> GetExpression<T>(string propertyName, string propertyValue)
{
    var parameterExp = Expression.Parameter(typeof(T), "type");
    var propertyExp = Expression.Property(parameterExp, propertyName);
    MethodInfo method = typeof(string).GetMethod("Contains", new[] { typeof(string) });
    var someValue = Expression.Constant(propertyValue, typeof(string));
    var containsMethodExp = Expression.Call(propertyExp, method, someValue);

    return Expression.Lambda<Func<T, bool>>(containsMethodExp, parameterExp);
}

...現在從您的方法中使用它:

public static List<Client> GetClientsByFilter(string search, string propertyName)
{
   //it's Entity Framework context
   using (var dbContext = new LibDbContext())
   {
        List<Client> clients;

             clients = dbContext.Clients
            .Where(GetExpression<Client>(propertyName, search)) // Now using Marc's method
            .ToList();
    }
 return clients;

}

由於“ GetExpression”是通用的,因此除了Client之外,您還可以輕松地將其重用於其他類型。 考慮重命名該方法,因為“ GetExpression”並不能說明您的意圖,例如“ GetPropertyContainsExpression”之類的東西。 如果propertyName中的值不是該類型上的有效屬性,並且當指定的屬性不是string類型(可能沒有采用字符串的Contains方法)時,您也可以考慮對該方法添加一些錯誤處理。 從表達式構建器在運行時可能引發的異常中,可能很難弄清這些錯誤。

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM