2010-11-20 5 views
0

C'est l'une des questions les plus difficiles que j'ai jamais eu à titre de titre ici sur SO. :) Bien que le titre pourrait ne pas avoir de sens, j'espère que la question elle-même le fera.Façon simple de transposer des données avant de passer aux fonctions?

Disons que j'ai une structure de données comme un Dictionary<string, List<double>>, et que je les fonctions qui prennent alors List<double> s comme paramètre:

Dictionary<string, List<double>> candy_positions = new Dictionary<string, List<double>>(); 
candy_positions.Add("Godiva", new List<double> { 1.0, 2.0, 4.0 }); 
EatCandy(candy_positions["Godiva"]); 
... 

Mais maintenant, j'ai décidé que je ne veux pas le faire par ici. Je veux remplacer mon Dictionary avec un List<CandyPositions>, où CandyPositions ressemble à ceci:

public class CandyPositions 
{ 
    public double Sees; 
    public double Godiva; 
    public double Lindt; 
} 

Cependant, je voudrais vraiment laisser EatCandy() seul. Évidemment, le problème est maintenant que mes données ne se prêtent pas directement à la méthode. Au lieu de cela, je dois faire quelque chose comme boiteux:

List<CandyPositions> candy_positions = new List<CandyPositions>(); 
... 
var positions = from x in candy_positions select x.Godiva; 
EatCandy(positions.ToList()); 

chaque fois que je veux appeler la méthode. Je préfère être en mesure de le faire d'une manière plus simple, comme:

EatCandy(candy_positions.GetPositionsFor("Godiva")); 

où le paramètre « Godiva » correspond au nom de la propriété dans la classe CandyPositions. Après avoir écrit cette question, j'ai réalisé qu'il ne s'agit pas vraiment de transposer des données - qu'une partie de celui-ci peut être manipulé en écrivant une méthode d'extension. La partie que je ne sais pas faire est de passer un nom de propriété, de sorte que la méthode d'extension puisse le prendre et l'associer à la propriété d'une classe. Je ne veux pas non plus passer une chaîne, surtout parce que cela ouvrira la porte à toutes sortes d'erreurs d'exécution. Je sais comment faire ce travail en passant "Godiva" à ma méthode d'extension. Ce que je veux vraiment passer, c'est quelque chose comme CandyPositions.Godiva à la place.

Cette question est probablement un peu confus, mais en résumé, j'accepterait le meilleur de deux types de réponses:

  1. Y at-il une meilleure façon de traiter les données transposent, que d'utiliser une méthode d'extension + un moyen d'accéder à un nom de propriété?
  2. Existe-t-il un moyen de spécifier la propriété que je veux que ma méthode d'extension récupère, autre que par une chaîne?

Ma méthode d'extension actuelle ressemble à ceci:

public static List<double> GetPositions(this List<CandyPositions> positions, string candy_name) 
{ 
    return (from x in positions select x.GetType().GetProperty(candy_name).GetValue(x, null)).Cast<double>().ToList(); 
} 

Répondre

1

Eh bien, vous pouvez utiliser:

public static List<double> GetPositions(this List<CandyPositions> positions, 
             Func<CandyPositions, double> projection) 
{ 
    return positions.Select(projection).ToList(); 
} 

et appelez avec:

EatCandy(candyPositions.GetPositions(x => x.Godiva)); 

D'autre part , si vous pouvez changer EatCandy pour accepter unà la place, vous n'avez pas besoin de la méthode supplémentaire - vous pouvez simplement utiliser:

EatCandy(candyPositions.Select(x => x.Godiva)); 

sans écrire une méthode supplémentaire du tout.

EDIT: Si vous devez itérer sur deux séquences à la fois, il y a deux options:

  • Si vous utilisez .NET 4, vous pouvez utiliser la méthode d'extension Zip.
  • Sinon, vous pouvez tout simplement écrire votre propre:

    using (var iterator1 = sequence1.GetEnumerator()) 
    using (var iterator2 = sequence2.GetEnumerator()) 
    { 
        while (iterator1.MoveNext() && iterator2.MoveNext()) 
        { 
         var value1 = iterator1.Current; 
         var value2 = iterator2.Current; 
         // Use the values here 
        } 
    } 
    
+0

whoa, approche très cool qui avait même pas eu pour moi. Merci, Jon! Et un commentaire hors sujet - Je suis ravi que ma commande pour votre nouveau livre C# arrive la semaine prochaine. :) – Dave

+0

Dans mon cas particulier, je ne peux pas utiliser IEnumerable car j'ai besoin d'accéder aux données par index seulement parce que j'ai deux listes, et une boucle qui fait quelque chose comme 'a [i] .foo (b [i]) '. Je l'ai toujours accepté comme le moyen de le faire, mais si vous connaissez une méthode cool qui me permet d'utiliser foreach et garder 'a' et' b' en synchronisation, s'il vous plaît faites le moi savoir! :) – Dave

+0

@Dave: Il existe des moyens absolus de le faire. Éditera. Heureux d'entendre que vous avez le livre sur son chemin - j'espère que vous l'apprécierez! –

Questions connexes