如何使用我不知道的通用参数返回函数?

时间:2011-05-11 21:32:47

标签: c# generics closures

我想调用一个生成函数的函数,但是在调用生成的函数之前我不知道类型参数:

ActionResult Foo() {
  IEnumerable<MyObject> list = GetList();

  var orderBy = OrderBy(list); // <-- HOW DO I WRITE OR DO THIS;

  switch(Request.QueryString["sortBy"]) {
    case "Name":
      return orderBy<string>(o => o.Name); // <-- SO I CAN MAKE THIS CALL
    case "TrackingNumber":
      return orderBy<int>(o => o.TrackingNumber); // <-- AND THIS ONE
    default:
      return View(list);
  }
}

在调用返回的函数之前,我不会知道T的类型。我想像这样生成函数,它将列表包装在一个闭包中,这样我就不必继续传递它。

Func<Func<MyObject,T>,ActionResult> OrderBy<T>(IEnumerable<MyObject> list) {
  Func<Func<MyObject,T>, ActionResult> f = orderBy => {
     return View(Request.QueryString["sortDir"] == "d"
        ? list.OrderBy<MyObject, T>(orderBy)
        : list.OrderByDescending<MyObject, T>(orderBy));
  };
  return f;
}

更新

我知道有更好的方法可以做到这一点。我想知道如何在闭包中包装此列表并返回一个具有我不知道的通用类型的函数。例如,由于在不知道类型的情况下我无法返回泛型类型函数,是否有某些类型可以替换它?

2 个答案:

答案 0 :(得分:2)

诀窍是确定两种类型共有的关注类型。在这种情况下,它是IComparable。您正在排序,stringint都是IComparable

你也使问题变得比它需要的复杂得多。你不需要这么多Func来返回Func。你可以简化。

此外,您不希望ASP.NET MVC类渗透到整个应用程序中。将这些内容保存在控制器中,让执行实际工作的代码采用参数,这样就不会知道它在ASP.NET MVC或Web中运行,并且可以进行单元测试。

    public static IEnumerable<MyObject> GetSortedList(string sortBy, bool sortAscending)
    {
        IEnumerable<MyObject> list = GetList();

        Func<MyObject, IComparable> keySelector;

        switch (sortBy)
        {
            case "Name":
                keySelector = o => o.Name;
                break;

            case "TrackingNumber":
                keySelector = o => o.TracingNumber;
                break;

            default:
                return list;
        }

        return sortAscending
                   ? list.OrderBy(keySelector)
                   : list.OrderByDescending(keySelector);
    }

答案 1 :(得分:1)

这应该这样做:

ActionResult Foo() {
  IEnumerable<MyObject> list = GetList();

  switch(Request.QueryString["sortBy"]) {
    case "Name":
      return OrderBy(list, o => o.Name); // <-- SO I CAN MAKE THIS CALL
    case "TrackingNumber":
      return OrderBy(list, o => o.TrackingNumber); // <-- AND THIS ONE
    default:
      return View(list);
  }
}

ActionResult OrderBy<T>(IEnumerable<MyObject> list, Func<MyObject, T> orderBy) {
    return View(Request.QueryString["sortDir"] == "d"
        ? list.OrderBy<MyObject, T>(orderBy)
        : list.OrderByDescending<MyObject, T>(orderBy));
}