J'examine un morceau de code que j'ai écrit il n'y a pas trop longtemps, et je déteste simplement la façon dont j'ai géré le tri - je me demande si quelqu'un pourrait me montrer une meilleure façon.
J'ai Une classe, Il ressemble à ceci: p> Un extrait court ci-dessous illustre le code: p> mon problème est avec l'instruction de commutation. Le commutateur code> code> est étroitement lié au Peut-être que quelqu'un peut me dire s'il y a une meilleure façon de trier ma liste? P> p> Holding code>, qui contient des informations. J'ai une autre classe,
HoldingsList code>, qui contient une liste
portfoliosheetMapping code>, qui a ~ 40 éléments ou donc des éléments. P>
portfoliosheetMapping code> Enum, qui peut changer demain ou le lendemain. Chaque fois qu'il change, je vais devoir revenir sur cette instruction de commutation et ajouter une autre affaire
code> en bloc. Je suis effrayé que finalement que cette déclaration de commutation augmente si grosse qu'elle soit totalement ingérable. P>
7 Réponses :
Avez-vous regardé dans Plus précisément, vous pouvez simplement faire quelque chose comme: p> note em> / Code> Propriété La première fois. Dans ces cas, Dynamiclinq aura besoin de voir, par exemple, "produit.productd" code>. Vous pouvez refléter le nom de la propriété ou simplement utiliser une valeur «bien connue» et une concurrence avec l'ENUM
.tostring () code>. À ce stade, je force ma réponse à votre question afin que cela soit au moins une solution de travail. P> p>
C'est une mauvaise réponse que je pense, on dirait "Lisez ceci, peut-être que cela aide et je suis trop paresseux pour vous aider à trouver une solution" =)
@Marc, merci pour le lien (pas de jeu de mots), mais comment cela aiderait-il à réduire mon énorme relevé de commutation?
Wow, je vais éditer mon message pour mettre quelque chose de spécifique et les déclencheurs itinérants sortent. Le ciel nous interdit que je suis un peuple lent de Typper! ;)
@Restuta: Code4Life travaille avec des données qui semble que cela semble être traité le plus efficacement dans une représentation de la base de données (la partie qui me démarquait était le fait que les données ont un ensemble de colonnes nommées, chacune peut être la colonne de tri. pour les données). Marc a posté un lien qui explique comment faire de telles requêtes de manière dynamique, ce que veut Code4Life.
@Marc, je pense que je n'étais pas clair. Pf.holdings est une liste
@Jab sans explication sa réponse n'est pas utile, cela est prouvé par le fait qu'il a modifié sa réponse.
Vous pouvez implémenter une classe Icomarer personnalisée qui utilise la réflexion. Cependant, cela serait plus lent.
Voici une classe que j'ai utilisée une fois: p> puis utilisez-le comme ceci: p> var comparer = new ListComparer() {
Field= frm.SelectedSortColumn.BaseColumn.ToString() };
if (frm.SortAscending)
pf.Holding = pf.Holding.OrderBy(h=>h.Product, comparer).ToList();
else
pf.Holding = pf.Holding.OrderByDescending(h=>h.Product, comparer).ToList();
Je suis prêt à regarder cela - pouvez-vous élaborer un peu plus sur la façon dont la réflexion serait utilisée? Je ne sais pas comment cela correspond à mon énoncé de commutation et aux valeurs d'énumération ...
Toutefois, si votre version-cadre le permet, je préférerais la solution dynamique LINQ!
Que diriez-vous:
Func<Holding, object> sortBy; switch (frm.SelectedSortColumn.BaseColumn) { case PortfolioSheetMapping.IssueId: sortBy = c => c.Product.IssueId; break; case PortfolioSheetMapping.MarketId: sortBy = c => c.Product.MarketId; break; /// etc. } /// EDIT: can't use var here or it'll try to use IQueryable<> which doesn't Reverse() properly IEnumerable<Holding> sorted = pf.Holdings.OrderBy(sortBy); if (!frm.SortAscending) { sorted = sorted.Reverse(); }
@Michael corrige l'original où j'avais copié le mal si, c'est correct maintenant oui?
C'est correct, mais je préférerais iEnumerable
@Michael Je ne suis pas sûr que cela fait une énorme différence, il semble que les ordres-médicaments-médicaments reviennent simplement un énumérateur inversé en interne de toute façon à en juger par la sortie du réflecteur, mais je reçois votre point de vue.
Vous pouvez essayer de réduire le commutateur à quelque chose comme ceci:
private static readonly Dictionary<PortfolioSheetMapping, Func<Holding, object>> sortingOperations = new Dictionary<PortfolioSheetMapping, Func<Holding, object>> { {PortfolioSheetMapping.Symbol, h => h.Symbol}, {PortfolioSheetMapping.Quantitiy, h => h.Quantitiy}, // more.... }; public static List<Holding> SortHoldings(this List<Holding> holdings, SortOrder sortOrder, PortfolioSheetMapping sortField) { if (sortOrder == SortOrder.Decreasing) { return holdings.OrderByDescending(sortingOperations[sortField]).ToList(); } else { return holdings.OrderBy(sortingOperations[sortField]).ToList(); } }
J'étais sur le point de suggérer un dictionnaire de classes de comparaison, mais c'est beaucoup Natre!
Merci pour le conseil! Ceci est certainement plus facile à coder, mais je pense que je vais aller avec la suggestion de @ Lukeh à utiliser .sort () au lieu de cela, car c'est un peu plus rapide. Mais conceptuellement la même approche que vous (à l'aide d'un dictionnaire, etc., etc.).
Il me semble qu'il y a deux améliorations immédiates que nous pouvons faire: p>
la logique qui utilise qui laisse toujours le commutateur frm.sortascendend code> pour décider entre
commanderby code> et
OrderByDescenscends code> est dupliqué dans chaque
case code>, et peut être retiré après le commutateur code> si le boîtier
S est modifié pour ne rien faire d'établissement de la clé de tri et le mettre dans un
Func code> p> li>
code> bien sûr - et cela peut être remplacé par une carte statique (dans un dictionnaire code> code>, dites) de
portfoliosheetcapping Code> à un
FUNC code> Prenant un
Tenir code> et renvoie la touche de tri. par exemple p> li>
ul>
Merci, ce sont de bonnes suggestions, aide définitivement à mieux moduler le code.
Vous ré-attribuez les données triées directement à votre propriété Vous pouvez utiliser une carte pour contenir pf.holdings code>, alors pourquoi ne pas contourner la surcharge de
Orderby code> et
Tolist Code> et utilisez simplement la liste
Trier CODE> A > Méthode directement à la place?
Comparaison
délégués pour toutes les tri prises en charge, puis appelez Trier (comparaison
avec le délégué approprié: p>
Bonne suggestion, vaut vraiment la peine d'être essayée.
Merci! Anecdotage le .sort code> est légèrement mais définitivement plus rapide que .orderby (). Tolist ().
Nice, je me demandais comment taper ma solution, c'est mieux: le garder encapsulé dans le délégué.
Si les propriétés de la classe de maintien (symbole, prix, etc.) sont le même type que vous pouvez effectuer les éléments suivants: qui affiche ensuite: P> Valeurs d'origine: Code>
Quantité = 2, prix = 5 code>
Quantité = 7, prix = 2 code>
Quantité = 1, prix = 3 code> p>
Valeurs triés par prix: code>
Quantité = 7, prix = 2 code>
Quantité = 1, prix = 3 code>
Quantité = 2, prix = 5 code> p> p>
J'aime l'idée de func. Les propriétés de la classe de détention sont des types différents. Je devrais donc adopter une approche modifiée de ce que vous suggérez, mais une bonne idée néanmoins.
Je viens de voir les autres réponses postées lorsque je faisais le mien et que vous pouvez changer la recherche à la recherche = nouveau dictionnaire
Pourquoi ce tri est-il fait? Est-ce seulement à des fins d'affichage?
@Hans, l'instance de classe est désérialisée à partir d'une feuille de calcul Excel contenant des données d'analyse de portefeuille. L'action réelle est appelée à partir d'un bouton de la barre d'outils Excel (mais c'est vraiment non pertinent), et une fois le tri terminé, je redésiomise les objets à la feuille de calcul. Le tri affecte réellement divers autres éléments de la feuille de calcul Excel, il n'est donc pas purement d'affichage uniquement.
S'étendant sur mon commentaire sur la réponse de Mark ... Serait-il possible que vous puissiez refactoriser votre code pour gérer les données dans un formulaire de type de base de données? Vous n'avez peut-être même pas besoin de l'énumé si vous avez utilisé un format de style plus de base de données (comme vous pouvez simplement ajouter et supprimer les colonnes de votre "table" au besoin), donc si vous êtes prêt à mettre dans le temps / effort à faire Ce refactoring, vous pourriez vous retrouver avec quelque chose de plus élégant, afin de parler. Bien sûr, il peut y avoir des aspects de votre programme ailleurs qui pourraient faire une telle approche moins réalisable qu'il ne semble ...
@ Code4Life: Ce n'est pas vraiment lié à votre question, mais si vous travaillez avec une feuille de calcul Excel, pourquoi avez-vous besoin d'extraire les données de cela comme ça? Êtes-vous incapable d'utiliser COM pour manipuler directement les données?
@Jab, eh bien les données proviennent d'une feuille de calcul d'analyse de portefeuille (Excel), donc dans la présente partie du cadre, la plupart des classes sont orientées vers la fonctionnalité de la feuille de calcul. Cela prendrait un refactoring important pour changer cela ... Je n'ai pas senti que cela était pertinent cependant, alors j'ai omis que cela indique le début.
@Jab, j'utilise vsto. L'utilisation de COM est une sorte de lent, donc je retire les gammes dont j'ai besoin d'un objet [] pour la manipulation de données. Les classes que j'ai sont plus ou moins façons pour le tableau, qui sont ensuite repoussées dans la feuille de calcul correspondante / gammes sur le classeur cible.
@ Code4Life: Ah, je vois. Ça a du sens.