[英]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檢查以執行OrderBy
或OrderByDescending
。
隱藏過濾器中的邏輯,然后您可以在應用中的任何位置重復使用它。
試試這個...輸入參數是字符串。 這是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.