2010-03-05 4 views
13

Я довольно новый (нормально, REALLY новый) для дженериков, но мне нравится их идея. Я собираюсь быть с несколько раскрывающихся списков на вид, и я хотел бы общий способ взять список объектов и преобразовать его в список SelectListItemsКак написать общий метод расширения IEnumerable <SelectListItem>

Что я сейчас:

public static IEnumerable<SelectListItem> ToSelectListItems(
    this IEnumerable<SpecificObject> items, long selectedId) 
    { 
     return 
      items.OrderBy(item => item.Name) 
      .Select(item => 
        new SelectListItem 
        { 
         Selected = (item.Id == selectedId), 
         Text = item.Name, 
         Value = item.Id.ToString() 
        }); 
    } 

Беда в том, что я должен повторить, что код для каждого раскрывающегося списка, как объекты имеют различные поля, которые представляют Text свойства SelectListItem

Вот что я хотел бы выполнить:

public static IEnumerable<SelectListItem> ToSelectListItem<T>(this IEnumerable<T> items, string key, string value, int SelectedId) { 
    // I really have no idea how to proceed from here :(
} 

ответ

20

Ну, вы могли бы сделать что-то вроде этого:

public static IEnumerable<SelectListItem> ToSelectListItems(
    this IEnumerable<T> items, 
    Func<T,string> nameSelector, 
    Func<T,string> valueSelector, 
    Func<T,bool> selected) 
{ 
    return items.OrderBy(item => nameSelector(item)) 
      .Select(item => 
        new SelectListItem 
        { 
         Selected = selected(item), 
         Text = nameSelector(item), 
         Value = valueSelector(item) 
        }); 
} 
+0

Отмените это, нужно было сделать ToSelectListItems :) – Dan

+1

Как бы это назвать и, в частности, использовать делегат 'selected'? – Dan

+0

Очень приятное решение! – Samuel

3

Для того, чтобы это работало, как написано, ваш тип T необходимо реализовать некоторый интерфейс, который обеспечивает Name и Id свойства:

public interface ISelectable 
{ 
    string Name { get; } 
    int Id { get; } 
} 

При этом в месте, вы можете сделать:

public static IEnumerable<SelectListItem> ToSelectListItems<T>(this IEnumerable<T> items, long selectedId) 
    where T : ISelectable 
{ 
    return 
     items.OrderBy(item => item.Name) 
     .Select(item => 
       new SelectListItem 
       { 
        Selected = (item.Id == selectedId), 
        Text = item.Name, 
        Value = item.Id.ToString() 
       }); 
} 

Это необходимо для использования свойств Name и Id в рамках вашего метода расширения ... Вместо этого вы могли бы предоставить различные способы их получения (то есть: передача делегатов), но это может или m не увеличивайте стоимость обслуживания в вашем сценарии.

+0

Друг, с помощью этого метода, как я бы используй это ? Выглядит чище, чем другие ответы. Благодаря ! –

8

Вы можете передать делегатам возможность выполнять сравнения и поиск свойств. Что-то вроде этого:

public static IEnumerable<SelectListItem> ToSelectListItem<T>(this IEnumerable<T> items, 
    int selectedId, Func<T,int> getId, Func<T, string> getName, 
    Func<T, string> getText, Func<T, string> getValue) 
{ 
    return 
     items.OrderBy(item => getName(item)) 
     .Select(item => 
       new SelectListItem 
       { 
        Selected = (getId(item) == selectedId), 
        Text = getText(item), 
        Value = getValue(item) 
       }); 
} 

Тогда вы будете использовать его следующим образом:

var selected = specificObjects.ToSelectListItem(10, s => s.Id, s=> s.Name, s => s.Name, s => s.Id.ToString()); 
+0

Вам также понадобится делегат getName (по запросу Бруно) - ссылка item.Name в предложении OrderBy в настоящее время не будет компилироваться. – itowlson

+0

Хмм, я хочу отметить как это, так и следующие вопросы в качестве ответов :). Оба они именно то, что я ищу! – Dan

+0

@itowlson - спасибо, я пропустил этот. –

Смежные вопросы