2009-03-11 12 views
0

Je suis curieux sur la façon dont le code suivant fonctionne, en particulier la partie contenant le contenu du délégué puisque je suis nouveau à ce sujet. En outre, y a-t-il des goulots d'étranglement dans le code, par exemple, l'utilisation d'un SortedDictionary serait-elle préférable à l'utilisation d'une liste, puis au tri à l'aide de LINQ? Ok, voici le code:Explique comment les délégués travaillent dans le code suivant?

public class ColorManager 
{ 
    private List<ColorData> colorCodes = new List<ColorData>(); 

    public List<ColorData> ColorCodes 
    { 
     get 
     { 
      var sortList = from a in this.colorCodes 
          orderby a.colorCode ascending 
          select a; 

      return sortList.ToList(); 
     } 
    } 

    public void FillData(DataTable table) 
    { 
     for(int row = 0; row < table.Rows.Count; row++) 
     { 
      ColorData cData = new ColorData(); 
      string name = table.Rows[row]["Color"].ToString().Trim(); 

      if(!this.colorCodes.Exists(
       delegate(ColorData e) 
       { 
        return e.ColorCode == name; 
       })) 
      { 
       cData.Add(table.Rows[row]["Color"].ToString()); 
       this.colorCodes.Add(cData); 
      } 
      else 
      { 
       this.colorCodes.Find(
        delegate(ColorData e) 
        { 
         return e.ColorCode == name; 
        }).Count++; 
      } 
     } 
    } 
} 

Répondre

2

Je suis curieux sur la façon dont le code suivant fonctionne, en particulier la partie contenant les choses du délégué depuis que je suis nouveau à lui.

Tout d'abord jeter un oeil à cette propriété accesseur ColorCodes:

 var sortList = from a in this.colorCodes 
         orderby a.colorCode ascending 
         select a; 

Il retourne une liste de tous les codes de couleur (this.colorCodes) dans l'ordre croissant (...orderby a.colorCode ascending). Simple jusqu'à présent. Que diriez-vous de la méthode plus riche FillData?

D'abord, nous allons boucler sur chaque ligne de ce tableau:

for(int row = 0; row < table.Rows.Count; row++) 
    { 

Ensuite, nous allons regarder la colonne Color de la ligne actuelle.

 ColorData cData = new ColorData(); 
     string name = table.Rows[row]["Color"].ToString().Trim(); 

Si cette colonne n'a pas de correspondance dans notre liste de codes de couleur, cette condition if est vrai. La méthode Exists prend une fonction à un seul argument qui retourne un bool, ce qui est ce que ce délégué anonyme est: une fonction à un seul argument (ColorData e) qui renvoie un booléen (e.ColorCode == name). Il est annulé (!this.[...]), donc si une correspondance est trouvée, la condition est fausse.

 if(!this.colorCodes.Exists(
      delegate(ColorData e) 
      { 
       return e.ColorCode == name; 
      })) 
     { 
      cData.Add(table.Rows[row]["Color"].ToString()); 
      this.colorCodes.Add(cData); 
     } 

Sinon, s'il y a un match, trouver le nom en utilisant un autre délégué anonyme et ajouter un au nombre d'éléments de cette couleur. Notez que ce code est quelque peu inefficace, puisque les deux délégués anonymes différents font vraiment la même chose et pourraient être partagés.

+0

Comment pourrait-il être refactorisé pour qu'ils soient partagés? – Xaisoft

+0

Vous pouvez utiliser une méthode anonyme à chaque fois qu'un délégué est attendu. Essayez var matchThisColor = nouveau Func (e => e.ColorCode == name) ;. –

0

C'est un délégué anonyme qui sert de critère de sélection pour l'expression de recherche. En mots, si la couleur est égale à la couleur donnée par le nom, elle retournera true et Find l'ajoutera à IEnumerable qu'elle génère. Si elle renvoie false, Find ne le contient pas. Il peut être écrit plus succinctement comme

p => p.ColorCode == name 
0

Exists et Find sont des méthodes d'extension génériques. Ils pour pour chaque boucle sur chaque élément de la collection. Passer au délégué un paramètre (défini comme "(ColorData e)"), et renvoyer un booléen.

0

délégués:

Les délégués dans cet exemple sont en oeuvre un procédé Func. Fondamentalement, ce que vous faites, est de créer une méthode à la volée qui prend un argument ColorData, et retourne un booléen.

Cela vous permet de faire vos appels Exists() et Find() sur chaque membre de votre collection IEnumerable pour vérification et filtrage.

Pour ce Classé Dictionnaire:

Si c'est le seul endroit que vous utilisez, vous seriez mieux en utilisant SortedDictionary, puisque vous ne seriez pas le recours en permanence. À l'heure actuelle, chaque fois que vous appelez ColorCodes, vous recourez. Un SortedDictionary serait constamment trié.

2

En fait, il y a plus de délégués que prévu. La requête LINQ:

 var sortList = from a in this.colorCodes 
         orderby a.colorCode ascending 
         select a; 

est en fait:

var sortList = this.colorCodes.OrderBy(a => a.colorCode); 

qui (pour LINQ to Objects) est le même que:

var sortList = this.colorCodes.OrderBy(delegate (ColorData a) { 
    return a.colorCode; 
}) 

Il utilise un délégué pour identifier l'élément pour trier par - c'est-à-dire "donné un ColorData, je vais vous donner le colorCode". Notez que beaucoup de select utilise aussi impliquent un délégué, mais pas dans ce cas (le trivial select a est enlevé par le compilateur).

Dans le code:

 if(!this.colorCodes.Exists(
      delegate(ColorData e) 
      { 
       return e.ColorCode == name; 
      })) 

nous utilisons un prédicat; "étant donné un ColorData, je vais vous dire si c'est une correspondance, en testant le nom pour l'égalité". Notez que name est ici "capturé" dans le délégué, ce qui implique des astuces assez complexes du compilateur (je ne les décrirai pas).


Ré efficacité; il est difficile d'être sûr, mais peut-être:

Dictionary<string, ColorData> items = new Dictionary<string, ColorData>(); 
    foreach(DataRow row in table.Rows) { 
     string name = row["Color"].ToString().Trim(); 
     ColorData cData; 
     if (items.TryGetValue(name, out cData)) { 
      cData.Count++; 
     } else { 
      cData.Add(name); 
      colorCodes.Add(cData); 
      items.Add(name, cData); 
     } 
    } 

Cela évite beaucoup de duplication, et utilise un dictionnaire pour trouver des valeurs plutôt que constamment en utilisant Contient/Rechercher. Dans de nombreux cas, un LINQ GroupBy aurait pu aider, mais pas dans ce cas, peut-être.

Questions connexes