2009-05-06 7 views
5

J'ai vu des exemples d'utilisation de 'T' pour rendre une méthode réutilisable pour des collections génériques de classes différentes, mais je ne l'ai jamais vraiment compris ou compris les échantillons.Comment refactoriser ces deux méthodes similaires en une seule?

Je me demande s'il serait possible de mettre les deux méthodes ci-dessous en une seule et quels en seraient les inconvénients (en termes de performances).

Quelqu'un?

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

SOLUTION

La solution que je:

utilisation

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

avec

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

Répondre

7

Sans implementiong une interface commune comme @Grzenio a suggéré, vous pouvez utiliser une méthode générique comme ceci:

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

Merci!C'était ce que je cherchais en premier lieu. Je vais essayer de mettre en place le vôtre et de voir si j'aime travailler avec elle –

+0

Hey ma réponse est identique et posté trois minutes avant cette réponse mais cette réponse obtient 3 votes et le mien zéro! OK Je vais voter de toute façon, si seulement pour avoir les paramètres génériques pour la fonction dans le bon ordre ... – Motti

+1

ToSelectList peut également être fait une méthode d'extension. – idursun

8

L'ancienne école serait de créer une interface commune pour les deux Département et Fonction:

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

Vous implémentez Description du Ministère pour le retour d.Code + " - " + d.Description. et écrire la fonction à utiliser cette interface au lieu de classes concrètes:

[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 ce qui concerne l'utilisation des médicaments génériques, sa ne va pas aider beaucoup dans ce cas, parce que

  • les objets que vous besoins passez, à mettre en œuvre Id et description
  • vous ne remettons pas ces objets, donc à cet égard que vous n'avez pas se soucier de la sécurité de type de médicaments génériques
+0

Ofcourse! Merci. J'étais trop coincé en pensant à ces échantillons avec 'T' que je n'avais pas réalisé qu'une interface était tout ce dont j'avais besoin. Merci beaucoup. –

+2

Je dirais que l'utilisation de génériques et de fonctions serait une meilleure chose à faire dans ce cas. Ensuite, vous n'avez pas à forcer un tas de classes à implémenter une interface. Vous pourriez vouloir utiliser cette fonction ToSelectList sur une classe qui n'a pas d'ID ou de description, et où l'ajouter ne serait pas très logique (ou par exemple la propriété Description devrait vraiment être appelée quelque chose d'autre). – Svish

+0

Merci Svish. Bon point. –

4

En fait, vous pouvez le faire avec une combinaison de génériques et de fonctions, quelque chose comme ça (non testé peut même pas compiler).

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

Puis vous pouvez l'envoyer avec les fonctions lambda appropriées (ou appeler directement).

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

} 
Questions connexes