2009-05-06 20 views
5

He visto algunas muestras del uso de 'T' para hacer que un método sea reutilizable para colecciones genéricas de diferentes clases, pero nunca he entrado en él ni entendido las muestras.¿Cómo refactorizar estos 2 métodos similares en uno?

Me pregunto si sería posible poner los 2 métodos a continuación en uno y cuáles serían los inconvenientes de hacerlo (en cuanto a rendimiento).

¿Alguien?

 [NonAction] 
     public List<SelectListItem> ToSelectList(IEnumerable<Department> departments, string defaultOption) 
     { 
      var items = departments.Select(d => new SelectListItem() { Text = d.Code + " - " + d.Description, Value = d.Id.ToString() }).ToList(); 
      items.Insert(0, new SelectListItem() { Text = defaultOption, Value = "-1" }); 
      return items; 
     } 

     [NonAction] 
     public List<SelectListItem> ToSelectList(IEnumerable<Function> functions, string defaultOption) 
     { 
      var items = functions.Select(f => new SelectListItem() { Text = f.Description, Value = f.Id.ToString() }).ToList(); 
      items.Insert(0, new SelectListItem() { Text = defaultOption, Value = "-1" }); 
      return items; 
     } 

SOLUCIÓN

La solución que utilicé:

uso

var departmentItems = departments.ToSelectList(d => d.Code + " - " + d.Description, d => d.Id.ToString(), " - "); 
var functionItems = customerFunctions.ToSelectList(f => f.Description, f => f.Id.ToString(), " - "); 

con

public static class MCVExtentions 
    { 
     public static List<SelectListItem> ToSelectList<T>(this IEnumerable<T> enumerable, Func<T, string> text, Func<T, string> value, string defaultOption) 
     { 
      var items = enumerable.Select(f => new SelectListItem() { Text = text(f), Value = value(f) }).ToList(); 
      items.Insert(0, new SelectListItem() { Text = defaultOption, Value = "-1" }); 
      return items; 
     } 
    } 

Respuesta

7

Sin implementiong una interfaz común como @Grzenio sugiere, se puede utilizar un método genérico de esta manera:

public List<SelectListItem> ToSelectList<T>(IEnumerable<T> enumerable, Func<T, string> text, Func<T, string> value, string defaultOption) 
    { 
     var items = enumerable.Select(f => new SelectListItem() { Text = text(f), Value = value(f) }).ToList(); 
     items.Insert(0, new SelectListItem() { Text = defaultOption, Value = "-1" }); 
     return items; 
    } 

    // use like 

    t.ToSelectList(departments, d => d.Code + " - " + d.Description, d => d.Id.ToString(), "default"); 
    t.ToSelectList(functions, f => f.Description, f => f.Id.ToString(), "default"); 
+0

¡Gracias!Esto era lo que estaba buscando en primer lugar. Trataré de implementar el suyo y veré si me gusta trabajar con él –

+0

¡Hola, mi respuesta es idéntica y la publiqué tres minutos antes de esta respuesta, pero esta respuesta obtiene 3 votos y la mía es cero! OK Votaré de todos modos, aunque solo sea para tener los parámetros genéricos para Function en el orden correcto ... – Motti

+1

ToSelectList también se puede convertir en un método de extensión. – idursun

8

La forma de la vieja escuela sería la creación de una interfaz común para ambas Departamento y Función:

interface A 
{ 
int ID{get;} 
string Description{get;} 
} 

Descripción Implementa el Departamento de volver d.Code + " - " + d.Description. y escribir la función de utilizar esta interfaz en lugar de clases concretas:

[NonAction] 
    public List<SelectListItem> ToSelectList(IEnumerable<A> as, string defaultOption) 
    { 
     var items = as.Select(a => new SelectListItem() { Text = a.Description, Value = a.Id.ToString() }).ToList(); 
     items.Insert(0, new SelectListItem() { Text = defaultOption, Value = "-1" }); 
     return items; 
    } 

EDIT: En cuanto a uso de los genéricos, esto no va a ayudar mucho en este caso, porque

  • los objetos que está pasando necesidades para implementar identificación y descripción
  • no están regresando estos objetos, por lo que en este sentido que no tiene que preocuparse por la seguridad de tipos genéricos de
+0

Por supuesto! Gracias. Estaba demasiado atrapado pensando en esas muestras con 'T' que no me di cuenta de que una interfaz era todo lo que necesitaba. Muchas gracias. –

+2

Diría que usar genéricos y funciones sería una mejor cosa que hacer en este caso. Entonces no es necesario obligar a muchas clases a implementar una interfaz. Es posible que desee utilizar esa función ToSelectList en una clase que no tenga una ID o Descripción, y donde agregarla no sería muy lógico (o, por ejemplo, la propiedad Descripción realmente debería llamarse algo más). – Svish

+0

Gracias Svish. Buen punto. –

4

De hecho, puedes hacerlo con una combinación de genéricos y funciones, algo parecido a esto (aún no probado puede que no compile).

[NonAction] 
public List<SelectListItem> ToSelectList<T>(IEnumerable<T> en, 
              Function<string, T> text, 
              Function<string, T> value, 
              string defaultOption) 
{ 
    var items = en.Select(x => new SelectListItem() { Text = text(x) , Value = value(x) }).ToList(); 
    items.Insert(0, new SelectListItem() { Text = defaultOption, Value = "-1" }); 
    return items; 
} 

A continuación, puede enviar a ella con las correspondientes funciones lambda (o llamar directamente).

[NonAction] 
public List<SelectListItem> ToSelectList(IEnumerable<Department> departments, 
             string defaultOption) 
{ 
    return ToSelectList<Department>(departments, d => d.Code + '-' + d.Description, d => d.Id.ToString(), defaultOption); 

} 
Cuestiones relacionadas