问题:
我有一个包含排序按钮的标题的html表。数据在控制器处获取,并根据传递的路由值(字符串)以OrderBy()
进行排序。我目前正在使用一个巨大的switch语句,需要对每列进行col_asc
和col_desc
检查以确定所请求的排序方法。我想尽可能减少这种情况并添加一个ThenBy
排序,它也将作为路由值传递。
Func<MProduct,int> orderByLambda;
switch (orderByColName)
{
case "asset_desc":
//models = models.OrderByDescending(m => m.AssetId);
orderByLambda = m => m.AssetId; // this is test code
break;
case "asset_asc":
models = models.OrderBy(m => m.AssetId);
break;
case "location_desc":
models = models.OrderByDescending(m => m.Locations.Name);
break;
case "location_asc":
models = models.OrderBy(m => m.Locations.Name);
break;
...... So on and so forth ......
case "manufacturer_desc":
models = models.OrderByDescending(m => m.Models.Manufacturers.Name);
break;
case "manufacturer_asc":
models = models.OrderBy(m => m.Models.Manufacturers.Name);
break;
default:
models = models.OrderByDescending(m => m.AssetId);
break;
}
所需的解决方案:
我想要做的就是将它拆开,只检查switch语句中的实际列名,并使用bool
检查asc / desc部分。 switch语句只会将所需的lambda表达式赋给变量(orderByLambda)。排序函数看起来像这样:
private IEnumerable<MProduct> Order(
List<MProduct> items,
bool isDescending,
Func<MProduct, int> orderByLambda)
{
if (isDescending)
{
return items.OrderByDescending(orderByLambda);
}
return items.OrderBy(orderByLambda);
}
我被困的地方
到目前为止这似乎有效(Visual Studio没有显示任何红色)。但是,由于我必须将lambda变量声明为类型Func<MProduct, int>
,因此我无法传递数据类型不是int
的列。我怎么能克服这个?有没有更好的办法?我正在研究dynamic
类型,但我并非100%确定它会起作用。
答案 0 :(得分:2)
您可以使Order
通用,但这意味着调用者需要指定列的类型。
private IEnumerable<MProduct> Order<T>(List<MProduct> items, bool isDescending, Func<MProduct, T> orderByLambda)
{
if (isDescending)
{
return items.OrderByDescending(orderByLambda);
}
return items.OrderBy(orderByLambda);
}
另一种解决方案是不传递依赖于列类型的func。 Order
方法将Action
带有一个参数,该参数本身就是一个通用方法,它将应用适当的订购方法:
private IEnumerable<MProduct> Order(List<MProduct> items, bool isDescending, Action<IApplyer<MProduct>> orderByLambda)
{
IApplyer<MProduct> applyer;
if (isDescending)
{
applyer = new OrderByApplyer<MProduct>(items);
}
else
{
applyer = new OrderDescendingByApplyer<MProduct>(items);
}
orderByLambda(applyer);
return applyer.Result;
}
// Usage
Order(items, true, a => a.Apply(o => o.Name));
Order(items, true, a => a.Apply(o => o.Age));
Dictionary<string, Action<IApplyer<MProduct>>> columns = new Dictionary<string, Action<IApplyer<MProduct>>>
{
["Name"] = a => a.Apply(o => o.Name),
["Age"] = a => a.Apply(o => o.Age),
};
Order(items, true, columns["Age"]);
//Implementation
interface IApplyer<TTarget>
{
void Apply<TColumn>(Func<TTarget, TColumn> orderBy);
IOrderedEnumerable<TTarget> Result { get; }
}
class OrderByApplyer<TTarget> : IApplyer<TTarget>
{
public OrderByApplyer(IEnumerable<TTarget> target)
{
this.Target = target;
}
public IEnumerable<TTarget> Target { get; }
public IOrderedEnumerable<TTarget> Result { get; set; }
public void Apply<TColumn>(Func<TTarget, TColumn> orderBy)
{
this.Result = this.Target.OrderBy(orderBy);
}
}
class OrderDescendingByApplyer<TTarget> : IApplyer<TTarget>
{
public OrderDescendingByApplyer(IEnumerable<TTarget> target)
{
this.Target = target;
}
public IEnumerable<TTarget> Target { get; }
public IOrderedEnumerable<TTarget> Result { get; set; }
public void Apply<TColumn>(Func<TTarget, TColumn> orderBy)
{
this.Result = this.Target.OrderByDescending(orderBy);
}
}
class ThenByApplyer<TTarget> : IApplyer<TTarget>
{
public ThenByApplyer(IOrderedEnumerable<TTarget> target)
{
this.Target = target;
}
public IOrderedEnumerable<TTarget> Target { get; }
public IOrderedEnumerable<TTarget> Result { get; set; }
public void Apply<TColumn>(Func<TTarget, TColumn> orderBy)
{
this.Result = this.Target.ThenBy(orderBy);
}
}
class ThenByDescendingByApplyer<TTarget> : IApplyer<TTarget>
{
public ThenByDescendingByApplyer(IOrderedEnumerable<TTarget> target)
{
this.Target = target;
}
public IOrderedEnumerable<TTarget> Target { get; }
public IOrderedEnumerable<TTarget> Result { get; set; }
public void Apply<TColumn>(Func<TTarget, TColumn> orderBy)
{
this.Result = this.Target.ThenByDescending(orderBy);
}
}