在变量

时间:2018-02-13 04:09:45

标签: c# asp.net-mvc lambda

问题:

我有一个包含排序按钮的标题的html表。数据在控制器处获取,并根据传递的路由值(字符串)以OrderBy()进行排序。我目前正在使用一个巨大的switch语句,需要对每列进行col_asccol_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%确定它会起作用。

1 个答案:

答案 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);
    }
}