2010-03-05 9 views
13

Soy bastante nuevo (bueno, REALMENTE nuevo) para los genéricos, pero me encanta la idea de ellos. Voy a tener unas listas desplegables en una vista y me gustaría una forma genérica para tomar una lista de objetos y convertirlo en una lista de SelectListItemsCómo escribir el método de extensión genérica IEnumerable <SelectListItem>

Lo que tengo ahora:

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

el problema es que había necesidad de repetir ese código para cada desplegable, como los objetos tienen diferentes campos que representan la propiedad de la TextSelectListItem

Aquí está lo que me gustaría lograr:

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 :(
} 

Respuesta

20

Bueno, usted podría hacer algo como esto:

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

Cancelar eso, tenía que hacer ToSelectListItems :) – Dan

+1

¿Cómo podría llamar esto y, en particular utilizar el delegado 'seleccionado'? – Dan

+0

¡Muy buena solución! – Samuel

3

Para que esto funcione como está escrito, el tipo de T habrá que poner en práctica alguna de las interfaces que proporciona Name y Id propiedades:

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

Con esto en su lugar, puede hacerlo:

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

Esto es necesario para utilizar las propiedades Name y Id dentro de su método de extensión ... En su lugar, podría proporcionar un medio diferente de recibirlas (es decir, pasar delegados), pero eso puede o m no aumente el costo de mantenimiento en su escenario.

+0

amigo, con este método, la forma en que lo haría usarlo? Parece más limpio que otras respuestas. Gracias ! –

8

Puede pasar delegados para hacer las comparaciones y la recuperación de propiedades. Algo como esto:

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

allí tendría que usarlo de esta manera:

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

También necesitaría un delegado getName (según la respuesta de Bruno): la referencia item.Name en la cláusula OrderBy no se compilará actualmente. – itowlson

+0

Hmm, quiero marcar tanto esta como las siguientes preguntas como respuestas :). ¡Ambos son exactamente lo que estoy buscando! – Dan

+0

@itowlson - gracias, me perdí esa. –

Cuestiones relacionadas