开发者

How can I return a function with generic parameters that I do not know ahead of time?

I want to call a function that generates a function, but I don't know the type parameter until I call the generated function like so:

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

I won't know th开发者_JAVA技巧e type of T until I call the returned function. I imagine something like this to generate the function, it wraps list in a closure so that I don't have to keep passing it around.

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;
}

Update:

I know there are better ways to do this. I want to know how I can wrap this list in a closure and return a function that has a generic type I don't know about ahead of time. For example, since I can't return the generic type function without knowing the type, is there some type I can replace it with?


The trick is to identify the type that you care about that both types have in common. In this case, it's IComparable. You're sorting, and both strings and ints are IComparable.

You're also making the problem a lot more complicated than it needs to be. You don't need so many Func's that return Func's. You can simplify.

Also you don't want ASP.NET MVC classes to permeate your entire application. Keep that stuff in the controllers and let the code that does the real work take parameters so it doesn't know it's running in ASP.NET MVC or in the web and can be unit tested.

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


This should do it:

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));
}
0

上一篇:

下一篇:

精彩评论

暂无评论...
验证码 换一张
取 消

最新问答

问答排行榜