6
votes

Downcasting en C #

Je suis confronté à un problème que je ne sais pas comment résoudre et espérons que la communauté peut aider.

J'écris une application qui gère des objets "plomb". (Ce sont des pistes de vente.) Une partie de mon programme importera des pistes d'un fichier texte. Maintenant, le fichier texte contient de nombreux prospects potentiels, dont je voudrais importer et certains dont je ne le ferai pas. P>

pour faciliter la programmation (et l'utilisation), je l'analyse du texte Fichier dans une liste objet et à l'aide d'un fichier DataGridView pour afficher les câbles en définissant la propriété DataSource du DataGridView. p>

Ce que je veux faire est d'ajouter une colonne à la grille, appelée "importation, "Avec une case à cocher que l'utilisateur peut vérifier si chaque plomb doit être importé ou non. P>

Ma première pensée consiste à dériver une classe de plomb:

public LeadWithImportCheckbox(Lead newlead)
{
  base.Property1 = newlead.Property1;
  base.Property2 = newlead.Property2;
  ....
  base.Property_n = newlead.Property_n;
}


2 commentaires

Juste une pensée aléatoire: est-il possible que vous souhaitiez suivre si un plomb était «importé» ou non (entré à la main)? En d'autres termes, pourrait-il être utile de faire importé une propriété permanente de dirige ?


Je ne pense pas que ce soit quelque chose que je voudrais suivre. Je vois les problèmes que cela résoudrait, mais cela ne fait vraiment pas partie de ce que je veux vraiment accomplir.


11 Réponses :


1
votes

Ce que vous voulez faire est d'afficher la colonne Cochez la case de votre réseau et ne l'avez pas connectée à vos objets en plomb. Vous utilisez les colonnes marquées (et la liste d'origine) pour créer un nouvel ensemble de liste qui sera votre liste d'importation.

puis gérer tout ce que vous souhaitez faire avec la liste nouvellement créée.

modifier : Une chose à faire preuve de prudence lorsque vous travaillez avec des listes, c'est le fait que chaque objet de classe n'est en réalité qu'un pointeur de la classe, donc si vous travaillez avec la liste d'origine et que vous faites quelque chose comme: xxx

que des objets existeront dans les deux listes et si vous modifiez des données d'un dirige sur l'une ou l'autre liste sera modifiée.


1 commentaires

J'ai demandé à l'origine cette solution. Cela fonctionne de manière appropriée si j'utilise une liste . Toutefois, si j'utilise un wrapper SDSAbAbindingList , les coches ne restent pas avec les câbles lorsque la DataGridView est triée. Étant donné que le fichier texte aura ~ 1 000 prospects potentiels, le tri est important. (Je m'excuse de ne pas y compris celui-ci dans la déclaration de problème initial; il est difficile de savoir combien d'informations suffit mais pas trop lors de la simplification d'un post.)



4
votes
public class LeadListItem
{
    public Lead Lead { get; set; }
    public bool ShouldImport { get; set; }
}
i.e. don't copy the Lead object's contents, just store a reference to it in a new LeadListItem object, which adds extra info "outside" the original object.If you want the properties of Lead to appear in the grid, there is almost certainly a way of doing that. Why not ask that question, instead of downvoting me for telling you the right answer to this question!

7 commentaires

Le problème avec cette solution est que les membres de plomb ne se présentent pas dans la DataGridView.


@Le Demigeek Voulez-vous, mais c'est une question différente.


Greenreign, comment est-ce une question différente? La question initiale portait sur l'affichage d'une avance avec une case à cocher dans un DataGridView. Une solution qui n'inclut pas les membres du plomb dans la DataGridView n'est pas une solution au problème.


La solution correcte à votre problème consiste à modéliser les données judicieusement avec des objets, puis à indiquer à la grille comment présenter le modèle afin qu'il affiche toutes les parties dont vous avez besoin. Ma réponse est la bonne réponse à la première partie, maintenant, vous devez trouver la deuxième partie. Cette deuxième partie est une question distincte.


@Le Demigeek ah, d'accord. Je vois maintenant, c'est ce que vous avez noté.


Pour l'énoncer succinctement, "préfère la composition sur l'héritage"


Earwicker fait un très bon point. Considérant que vous avez au moins 4 réponses qui copient essentiellement le sien, j'y penserais plus ... mais vous avez vos raisons, alors ...



3
votes

Quelques options que vous avez peut-être manquées:

  • Vous pouvez mettre à jour l'objet principal lui-même pour avoir une propriété d'importation (qui par défaut sur FALSE).
  • Vous pourriez avoir votre objet "ImporleLead" traiter le fil en tant que charge utile (même le rendre générique, si vous le souhaitez), vous n'avez donc pas besoin du grand constructeur.
  • Construisez une nouvelle liste d'objets de plomb ou en-témoine que contient uniquement les objets que vous souhaitez importer en premier lieu.

3 commentaires

J'irais avec la création d'une propriété d'importation sur la classe principale elle-même


Beaucoup plus éloquemment déclaré que ma tentative maladroite ci-dessus, mais à peu près ce que j'essayais de dire.


Je devrais être en désaccord avec Stan. Il n'y a aucune raison de la propriété d'importation sur la tête, elle est totalement sans rapport avec la tête et la pollution de votre objet de domaine. Ce n'est qu'un artefact de l'interface utilisateur et il ne faut donc pas modifier les objets de votre domaine de toute façon.



1
votes

Vous ne pouvez que baisser uniquement, si l'objet à baisser est vraiment un objet de ce type.

Un moyen plus facile de résoudre votre problème serait d'avoir une classe DisplayLead, telle que: xxx

qui vous aiderait également à séparer les données stockées de leur représentation dans une interface graphique.


2 commentaires

Si je fais cela, les propriétés du plomb ne vous apparaissent pas dans la DataGridView.


Avec les informations que vous avez fournies en réponse à mon message, c'est la solution optimale. Ce que vous devez faire est d'éteindre les colonnes de générer automatiquement et de créer manuellement les colonnes et d'utiliser des expressions de base de données pour atteindre les éléments de conteneur réels afin de pouvoir lire des objets complexes. Si vous recherchez C # DataBinding Eval ou similaire dans Google, vous devriez voir comment le faire.



0
votes

En tant que solution rapide et sale, vous pouvez créer votre objet "Cochez la case" comme objet différent contenant une instance de plomb. xxx

de cette façon, vous pouvez facilement ajouter plus de "grille" Propriétés à cet objet, tout en conservant toujours une référence aux détails de la tête sans cloner de la propriété du code papier.


1 commentaires

Si je fais cela, les propriétés du plomb ne vous apparaissent pas dans la DataGridView.



0
votes

vous recommande d'essayer de modifier (mettre à niveau) vos objets de plomb importés.

Essayez de commencer par les exemples ici ...


0 commentaires

1
votes

Je ne peux pas descendre à quelque chose que ce n'est pas le cas. Si l'objet a été instancié sous la forme d'un dirigeant , il ne peut pas être bumé à une classe dérivée. S'il était instancié sous la forme d'un LeadwithimportCheckbox puis retourné à votre code sous forme lead , vous pouvez le refuser.

ProTrip: Type de contrôle au moment de l'exécution avec est opérateur.


0 commentaires

0
votes

Si votre classe de plomb possédait un constructeur de copie (par exemple, le plomb (p. Extra enfermé) "), leadwithimportCheckbox hériterait et vous pouvez simplement appeler le constructeur principal de base dans le constructeur duadwithImpportCheckbox - Par conséquent, aucun besoin de leadwithImpportCheckBeCheckBeCKECKECKECKECKECKE détails de plomb.


0 commentaires

1
votes

Il y a de nombreuses façons de faire cela, mais la «bonne» façon apparaît à cause de ce que vous avez dit, ici:

Pour faciliter la programmation (et l'utilisation), je suis analyser le fichier texte dans un Liste d'objet, et à l'aide d'un DataGridView pour afficher les prospects par Définition de la propriété DataSource de la DataGridView.

Ce que je veux faire, c'est ajouter une colonne à la grille, appelée "importation" avec un case à cocher que l'utilisateur peut vérifier à indiquer si chaque avance ou non devrait être importé.

Votre Lead L'objet se situe bien seul et vous souhaitez attacher des métadonnées à celle-ci - vous ne voulez pas créer un autre fichier Classification (c.-à-d. Le LeadwithimportCheckbox Classe).

Ainsi, la meilleure approche dans votre cas consiste à avoir une classe comme: xxx

Ceci va bien augmenter lorsque vous souhaitez ajouter plus de métadonnées à votre liste, comme si vous souhaitez vous envoyer des rappels de courrier électronique à leur sujet chaque semaine.


1 commentaires

Mais si je fais cela, les propriétés principales ne s'affichent pas sur la DataGridView.



7
votes

ou, pour éviter l'aspect pita, utilisez la réflexion ... (essayez ceci ...)

Modifier: Utilisez la propriété, pas de champ comme je l'avais initialement écrit ... p>

public class NewLead : Lead
{
    public bool Insert;
    public NewLead(Lead lead, bool insert)
    {
        Insert = insert;
        foreach (PropertyInfo pi in typeof(Lead).GetProperties())
            GetType().GetProperty(pi.Name).SetValue
               (this, pi.GetValue(lead,null), null);
    }
}


3 commentaires

Je pense qu'en fin de compte j'aime l'approche de réflexion. (Je ne manque pas de la compréhension.) Dans votre code d'échantillon, je reçois un tableau de longueur zéro de typeof (plomb) .tfields ()


Je crois que c'est la solution que je vais m'installer. Merci, Charles! Le code que j'ai mis en œuvre et qui semble fonctionner est:


Solution fantastique. J'aime ne pas avoir à mettre à jour manuellement mon constructeur si la classe de base change.



1
votes

J'ai vu la solution correcte répertorie tant de fois que je me sens comme un talon qui le pose à nouveau, mais le meilleur moyen d'aborder cela consiste à écrire une enveloppe pour l'objet principal qui inclut le drapeau d'importation.

Si les propriétés de l'objet LEAD n'apparaissent pas dans la grilleView car vous êtes en train de diffuser sur l'objet, écrivez ensuite des propriétés passées qui reflètent les propriétés principales de l'objet wrapper.

Le problème est que vous souhaitez que quelque chose affiche à l'utilisateur qui ne soit pas une partie inhérente du modèle de données. La réponse consiste à envelopper les données avant de la présenter à l'utilisateur afin que vous puissiez contrôler ce qu'ils voit sans changer le modèle sous-jacent.

Si vous craignez que l'objet principal puisse changer tant de fois à l'avenir que des modifications apportées à l'enveloppe seront encombrantes, vous pouvez examiner la génération de code dynamique basée sur l'objet principal qui générera automatiquement un objet wrapper avec le mêmes champs que l'objet principal plus le drapeau d'importation. Bien que franchement, c'est beaucoup plus de travail que vous aurez probablement besoin de quelque chose de plus simple que cela.


2 commentaires

Je ne crois pas que ce soit la solution optimale. Si la structure de l'objet de plomb sous-jacent change, je dois revenir en arrière et éditer le code qui lie les propriétés de la direction à la DataGridView. L'héritage résout ce problème. Peu importe les changements apportés à mener, si leadwithimportCheckbox hérite de plomb, alors je n'ai pas besoin de modifier de code. Et «leadthatimightwanttoimport 'est-un« plomb ». L'héritage est approprié. Je crois que l'utilisation de la réflexion, comme le suggère Charles, sera la bonne façon de créer une boîte de plomb de plombhithimportcheck.


L'approche de réflexion atténuerait la question des «changements d'objet principal sous-jacents», mais comme je l'ai dit, si votre objet principal change cela souvent, il existe souvent des problèmes plus profonds que vos pratiques de codage. Sur la base de votre réponse à la solution de Charles, je ne suis pas sûr que la réflexion sera la bonne façon de vous assurer non plus. Notez également que l'utilisation de la réflexion de cette manière imposera une pénalité de performance grave (pourrait être un problème si vous commencez à avoir plusieurs milliers de prospects).