【问题标题】:Store a Lambda expression with multiple possible out types in a variable将具有多种可能输出类型的 Lambda 表达式存储在变量中
【发布时间】:2018-02-13 04:09:44
【问题描述】:

问题:

我有一个带有包含排序按钮的标题的 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&lt;MProduct, int&gt;,因此我无法传递数据类型不是int 的列。我该如何克服呢?有没有更好的办法?我正在研究 dynamic 类型,但我不能 100% 确定它会起作用。

【问题讨论】:

  • 您只需将Func&lt;MProduct, int&gt; 更改为Func&lt;MProduct, object&gt;,它在您的情况下应该可以正常工作。

标签: c# asp.net-mvc lambda


【解决方案1】:

您可以将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);
}

另一种解决方案是不传递依赖于列类型的函数。 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);
    }
}

【讨论】:

  • 这种方法有很多我喜欢的地方,但目前我觉得有点过头了。现在已经很晚了,我没有时间过夜,但我会深入研究它,学习一两件事,然后标记为已接受。谢谢!
  • @TylerSells 很高兴为您提供帮助,如果我能提供任何信息,请不要犹豫:)
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2017-09-15
  • 1970-01-01
  • 1970-01-01
  • 2015-03-09
  • 2014-02-20
相关资源
最近更新 更多