#c# #generics #closures
#c# #общие #замыкания
Вопрос:
Я хочу вызвать функцию, которая генерирует функцию, но я не знаю параметр типа, пока не вызову сгенерированную функцию следующим образом:
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;
}
Обновить:
Я знаю, что есть лучшие способы сделать это. Я хочу знать, как я могу обернуть этот список в замыкание и вернуть функцию, которая имеет общий тип, о котором я заранее не знаю. Например, поскольку я не могу вернуть функцию универсального типа, не зная типа, есть ли какой-нибудь тип, которым я могу ее заменить?
Комментарии:
1. Re: Ваше обновление. Смотрите мой ответ ниже. Если вы укажете
Func<MyObject, T>
, тип, о котором вы говорите, определяется автоматически. Дляo => o.Name
этогоstring
, дляo => o.TrackingNumber
этогоint
и так далее… Вы неявно указываете этот тип, выбирая одно из свойств вашего класса в качестве ключа сортировки.
Ответ №1:
Хитрость заключается в том, чтобы определить тип, о котором вы заботитесь, который является общим для обоих типов. В данном случае это IComparable
. Вы сортируете, и string
s и int
s являются IComparable
.
Вы также делаете проблему намного сложнее, чем это должно быть. Вам не нужно так много Func
‘s, которые возвращают Func
‘s. Вы можете упростить.
Также вы не хотите ASP.NET Классы MVC, которые пронизывают все ваше приложение. Храните это в контроллерах и позвольте коду, который выполняет реальную работу, принимать параметры, чтобы он не знал, что он выполняется в ASP.NET MVC или в Интернете и может быть модульно протестирован.
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. Имя и номер отслеживания зависят от пользовательского интерфейса. Вот почему они находятся в контроллере. Мой уровень обслуживания ничего не знает об этих элементах. Весь этот код, который я опубликовал, находится в моем контроллере. Я также знаю этот запрос. QueryString уступает, однако я застрял в поддержании существующего приложения MVC, первоначально написанного в версии 1.0, и это то, с чем мне приходится работать в данный момент.
2. хотя ваш ответ на самом деле не ответил на мой конкретный вопрос, это гораздо лучший способ реализовать это. Я просто пытался посмотреть, смогу ли я выполнить эту технику. В f # приложения с частичными функциями не редкость. Я продолжаю пытаться понять, что я могу применить к своему c #, который я пишу на работе каждый день.
Ответ №2:
Это должно сделать это:
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));
}
Комментарии:
1. ваш ответ не завершает список замыканием, он передает его методу, сводя на нет цель моего вопроса.