簡體   English   中英

在Method參數中包含OrderBy委托

[英]Include OrderBy delegate in Method parameters

我有一個方法;

    public List<Task> GetTasksByAssignedTo(Guid contactId)
    {
        List<Task> tasks = dc.Tasks.Where(x => x.ContactId == contactId).ToList();
        return tasks;
    }

它返回一個項目列表。 說我現在想要指定我想要返回列表的排序順序。

所以我可能按名稱,截止日期,完成等等排序等。

我怎么能在方法中包含它作為參數? 我不想使用switch語句,而是如果可能的話我想使用lambda。

所以;

List<Task> list = GetTasksByAssignedTo("guid", ??????);

或者這是錯誤的方法。

我認為你的方法是使用LINQ錯誤方法

LINQ使用延遲執行模型是有原因的。 它允許您將一系列操作鏈接在一起,只有當您告訴它計算結果時才會執行 - 通常使用.ToList() .ToArray() .ToList() .ToArray() .First() - 但您也可以通過過濾強制計算一個使用Func<T, ?>作為參數的OrderBy子句。

現在你要返回一個List<Task> ,這意味着你已經強制執行 - 當你准備好使用結果時這是正確的事情 - 但如果你繼續進行進一步的操作你可能將更多記錄加載到內存中,而不是需要。

你當然可以這樣做:

public List<Task> GetTasksByAssignedTo<P>(Guid contactId, Func<Task, P> orderBy)
{
    return dc.Tasks
        .Where(x => x.ContactId == contactId)
        .OrderBy(orderBy) // this forces evaluation - sort happens in memory
        .ToList();
}

要在數據庫中執行,您需要更改它:

public List<Task> GetTasksByAssignedTo<P>(
    Guid contactId,
    Expression<Func<Task, P>> orderBy)
{
    return dc.Tasks
        .Where(x => x.ContactId == contactId)
        .OrderBy(orderBy)
        .ToList(); // Now execution happens here
}

但問題是,如果你這樣做:

var query =
    from t1 in GetTasksByAssignedTo(contactId, t => t.Name)
    join t2 in GetTasksByAssignedTo(contactId, t => t.Name)
        on t1.Name equals t2.Name
    select new { t1, t2 };

因為GetTasksByAssignedTo將記錄帶入內存,所以你在內存中進行連接。 (是的,查詢有點人為,但原則很扎實。)

在數據庫中執行它通常要好得多。

以下是修復方法:

public IQueryable<Task> GetTasksByAssignedTo<P>(
    Guid contactId,
    Expression<Func<Task, P>> orderBy)
{
    return dc.Tasks
        .Where(x => x.ContactId == contactId)
        .OrderBy(orderBy);
}

現在,在您執行query.ToList()之前,上述查詢將不會執行,並且所有查詢都將在數據庫中發生。

但我有一個更大的問題。

您在GetTasksByAssignedTo隱藏了大量信息。 使用代碼的人不知道他們在讀取代碼時實際上是在獲取列表,而他們實際上並不知道實際的實現是否做得對。 我認為,對於這些類型的查詢,通常最好將其保留為簡單的LINQ。

比較這些:

var tasks1 = GetTasksByAssignedTo(contactId);
var tasks2 = GetTasksByAssignedTo(contactId, t => t.Name);
var tasks3 = GetTasksByAssignedToDescending(contactId, t => t.Name);

var tasks4 = (
        from t in dc.Tasks
        where t.ContactId == contactId
        orderby t.Name descending
        select t
    ).ToList();

第一個查詢, tasks1也不錯,但它不會告訴你返回類型是什么;

第二個查詢, tasks2做了一些t和屬性Name ,但沒有告訴你什么。

第三個查詢, tasks3給你一個提示,它正在排序降序,但不會告訴你它是否由神秘的Name屬性或其他東西。

第四個查詢, tasks4告訴你需要知道的一切 - 它是ContactId的過濾任務,按Name反向排序結果,最后返回一個列表。

現在,看一下這個查詢:

var query2 =
    from t1 in dc.Tasks
    where t1.ContactId == contactId
    join t2 in dc.Tasks on t1.Name equals t2.Name
    where t2.ContactId != contactId
    orderby t2.Name descending
    select t2;

我可以很容易地閱讀它,看看它在做什么。 試想一下這個幫助方法的名稱是什么! 或者需要什么樣的輔助方法的瘋狂嵌套。

底線是LINQ是用於查詢的API。

如果您迫切想要創建輔助方法,那么使用擴展方法

public static class TaskEx
{
    public static IQueryable<Task> WhereAssignedTo(this IQueryable<Task> tasks,
        Guid contactId)
    {
        return tasks.Where(t => t.ContactId == contactId);
    }

    public static IQueryable<Task> OrderByName(this IQueryable<Task> tasks)
    {
        return tasks.OrderBy(t => t.Name);
    }
}

這允許你寫這個:

var tasks = dc.Tasks
    .WhereAssignedTo(contactId)
    .OrderByName()
    .ToList();

這是清晰,簡潔,可擴展,可組合,可重用,並且您可以在執行時進行控制

您可以將Func<Task, object>傳遞給您的方法進行排序:

public List<Task> GetTasksByAssignedTo(Guid contactId, Func<Task, object> someOrder)
{
    List<Task> tasks = dc.Tasks.Where(x => x.ContactId == contactId)
                               .OrderBy(someOrder)
                               .ToList();
    return tasks;
}

現在你可以調用你的方法了

Func<Task, object> someOrder = (Task t) => t.DueDate;
List<Task> list = GetTasksByAssignedTo(someGuid, someOrder);

一般來說,我同意這些評論 - 似乎不需要對名為GetTasksByAssignedTo的方法進行GetTasksByAssignedTo

@BrokenGlass打敗了我。

另一種選擇是使用隱藏交換機的擴展方法,並將不同的排序選項表示為枚舉。

public static IEnumerable<Task> WithOrdering(this IEnumerable<Task> source, TaskOrdering order)
{
   switch (order)
   {
      case TaskOrdering.Name:
         return source.OrderBy(task => task.Name);
      case TaskOrdering.DueDate:
         return source.OrderByDescending(task => task.DueDate);       
   }
}

然后:

public List<Task> GetTasksByAssignedTo(Guid contactId, TaskOrdering order)
{
    List<Task> tasks = dc.Tasks.Where(x => x.ContactId == contactId)
                               .WithOrdering(order)
                               .ToList();
    return tasks;
}

我一直這樣做。 允許謂詞作為方法參數可能很棘手,因為如果你想進行升序/降序會發生什么? 您需要另一個參數(bool),然后執行if / else檢查以執行OrderByOrderByDescending

隱藏過濾器中的邏輯,然后您可以在應用中的任何位置重復使用它。

試試這個...輸入參數是字符串。 這是StackOverflow的修改解決方案

    /// <summary>
    /// Sort List<typeparam name="T"></typeparam> objects base on string options
    /// </summary>      
    /// <param name="SortDirection">Ascending or Descending</param>   
    /// <param name="ColumnName">Column name in complex object (object.ColumnName)</param> 
 public static class ListExtension
{
    public static List<T> SortList<T>(this List<T> data, string sortDirection, string sortExpression)
    {
        try
        {
            switch (sortDirection)
            {
                case "Ascending":
                    data = (from n in data
                            orderby GetDynamicSortProperty(n, sortExpression) ascending
                            select n).ToList();
                    break;

                case "Descending":
                    data = (from n in data
                            orderby GetDynamicSortProperty(n, sortExpression) descending
                            select n).ToList();
                    break;

                default:
                    data = null; //NUL IF IS NO OPTION FOUND (Ascending or Descending)
                    break;

            }
            return data;
        } catch(Exception ex){
            throw new Exception("Unable to sort data", ex);
        }
    }

    private static object GetDynamicSortProperty(object item, string propName)
    {
        //Use reflection to get order type          
        return item.GetType().GetProperty(propName).GetValue(item, null);
    }

}

暫無
暫無

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

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