7
votes

Comment les données supplémentaires peuvent-elles être associées à des objets existants à l'aide de méthodes d'extension?

Depuis .NET Framework 3.5, les développeurs ont pu ajouter des méthodes d'extension appelables à des instances de tout type d'objet. Les propriétés d'extension n'ont toutefois pas été implémentées dans C #. Contrairement aux méthodes d'extension, les propriétés d'extension impliqueraient de stocker des informations supplémentaires sur l'état pour des objets individuels.

Toutefois, même pour les méthodes d'extension, il serait très utile de certains scénarios de programmation pour pouvoir accéder aux informations postérieures / extensions pour les objets sur lesquels ces méthodes d'extension sont appelées.

Voici la question originale: Comment ajouter des propriétés d'extension ou définir des données étendues sur un objet en C #?


9 commentaires

Quelle est la question?


"Comment peut-on ajouter des données associées à des objets existants?" C'est comme ça que je l'ai lu - j'attends sa réponse de soi; Je sais comment faire avec les objets RCW, mais pas en général.


Pourquoi voudriez-vous faire cela? Ne sont pas assez de composition normale ni de héritage?


Pas toujours, @svick. On ne peut pas toujours prolonger une classe existante, mais peut-être peut-être ajouter des méthodes d'extension. En outre, utiliser ces idées, on peut se rapprocher de l'utilité des propriétés de vulgarisation. J'ai évoqué votre commentaire, cependant.


Vous pouvez ajouter des méthodes d'extension pour les structures et les enums.


Les méthodes d'extension sont différentes, elles ajoutent des fonctionnalités, pas d'état, ce qui, je pense, fait beaucoup plus de sens. Bien qu'il soit vrai que les propriétés attachées sont parfois utiles dans WPF.


@Lee, corrigé - l'idée que j'essayais d'exprimer est vraiment que cela fonctionnera pour des types d'objets mais non des structures ou des énumérations.


@svick, je n'ai pas encore d'expérience avec WPF. J'essaie juste de me libérer du désordre de devoir stocker de l'extérieur et de passer à des méthodes d'extension des informations utiles. Ce type de situation semble abattre partout où il y a une API tierce partie avec beaucoup de petits objets générés en interne, qui devront peut-être être manipulé, mais où le code à faire doit donc appeler sans cesse des méthodes d'usine pour les mêmes objets contextuels anciens, etc. Si un contexte supplémentaire pourrait être attaché à des éléments, le code appelant peut toujours y avoir un accès direct quand il est utile, mais être libéré de la complexité.


Je suis stupéfié que cela a été fermé comme «pas une vraie question». Il n'est pas difficile de dire ce qui est posé - la question est clairement comment ajouter des propriétés ou d'autres données étendues à un objet au moment de l'exécution. Non seulement c'est une question valable, elle a une réponse réelle et valide qui a été indiquée à être telle de quatre personnes après avoir présumé des bowvotes.


3 Réponses :


11
votes

the System.Runtime.Compilerservices.conitionnementalweakTable classe semble être Ce que le médecin a ordonné, et ne semble pas impliquer le genre de fuite de mémoire soucie que d'autres approches pourraient soulever. Voici mon premier wrapper simple autour de l'utilisation de conditionnés. Je vais les cacher un peu mieux (rendez-les internes et plus obscurement nommés) et mettre d'autres méthodes devant eux, mais cela fonctionne et est un grand soulagement et aide pour moi.

(Merci à Svick, Jeppe Stig Nielsen, Tormod et user2246674 pour m'aider à penser cela à travers.) xxx

( modifier : la réponse originale suit, à des fins historiques.)

La méthode System.componentModel.typeDescriptor.getTtributes (objet) expose une collection d'objets système.Attribute ajoutés à l'objet spécifié. Ainsi, si un attribut a été ajouté à un objet (mais pas une structure ou une énumération), capable de stocker des paires de la valeur de clé, ces paires pourraient être accessibles via des méthodes d'extension, masquant le mécanisme de stockage à partir du code d'appel. Ceci n'est pas aussi propre que les propriétés d'extension seraient, en raison de la méthode inévitable Syntaxe PCALL, mais est toujours utile dans certains scénarios de programmation.

Étant donné que l'objet stockant les données doit hériter de System.Attribute, et il est inconnu à l'avance Quel type de données devra être stockée, une solution simple consiste à créer une classe qui hérite à partir du système. Attribut et implémente le cahicotement. Les méthodes d'extension faciles à utiliser peuvent ensuite être apportées pour envelopper l'utilisation de cette classe, simplifiant ainsi le stockage et la récupération des données d'extension.

Suivant est code pour une telle mise en oeuvre: xxx

... et certaines méthodes d'extension génériques pour enrouler un peu plus loin: XXX

... et, enfin, deux exemples de méthodes d'extension personnalisées pour utiliser cette idée dans le code du monde réel. On utilise la classe ExtensionDataAattribute directement (et est donc un peu plus de boulons et de boulons), l'autre utilise les méthodes d'extension génériques fournies ci-dessus: xxx

J'espère que ces idées ont été utiles. On n'a pas toujours le luxe d'étendre une classe et, dans certaines situations, il peut apporter la conception des méthodes d'extension si on ne doit pas nécessairement assembler et passer des informations supplémentaires avec chaque appel de méthode, sur un objet qui peut ne pas avoir été créé dans le code de la fabrication du développeur du tout.


2 commentaires

Très intelligent - heureusement, je ne peux pas dire que j'ai besoin Ceci (il est plus facile d'éviter un besoin si vous commencez avec suppos que ce n'est pas possible), mais de toute façon intelligente. J'imagine que le graphique de l'accessibilité de l'objet est toujours pris en charge par les données supplémentaires ne démarrait pas une "fuite de mémoire"?


@ user2246674: merci! J'étais heureux quand je l'ai compris. Votre question est une bonne. Je suppose que la réponse est "Oui", puisque System.Attribute est librement extensible, car par la conception, il peut être attaché à des objets individuels ainsi que des types, et parce que de nombreux attributs ont des valeurs de données qui sont attachées à ceux qui sont inconnus au moment de la compilation , plus peut être mutable. Je suppose que votre question est la même que: les instances System.Artribute sont-elles internées d'une manière ou d'une autre? Je ne trouve aucune référence à ce sujet mais je vais tester ...



0
votes

Bien sûr qu'il y a. Tout ce dont vous avez besoin est un dictionnaire accessible à celui qui interagit avec les données. Chaque fois que vous avez besoin des données que vous appelez TheDataStore [TheObject] et récupérez l'objet de valeur contenant quelles que soient les propriétés que vous désirez.

Au niveau abstrait, un tel magasin d'établissement est comment propriétés connectées Travailler dans WPF.


3 commentaires

Oui, on peut utiliser des collections externes. J'ai édité la question de la rendre plus claire. L'idée est de savoir si on peut ou non attacher des données à des objets individuels, sans utiliser de héritage, de manière assez propre. La méthode que j'ai montrée est une sorte d'approche de Rube Goldberg en ce qu'elle utilise des attributs d'une manière pour laquelle ils n'étaient pas destinés, mais il semble fonctionner assez bien et peut entraîner un code d'appel propre, qui est enregistré de devoir avoir connaissance des structures de données externes et similaires.


Puisque vous avez mentionné des méthodes d'extension, vous pouvez accéder aux collections statiques en eux. Fondamentalement, avoir des méthodes d'extension implémentent des getters / setters. Méfiez-vous que vous souhaitiez peut-être examiner le sujet des faibles références car les collections statiques de références standard empêcheront d'être recueillies.


Vos commentaires et ceux ci-dessous ont conduit à ce que je ressens est la meilleure approche ... Aller modifier ma réponse précédente. Voyez si vous l'aimez. Merci!



0
votes

Je pensais quelque chose comme: XXX

Ceci est juste un croquis, bien sûr. Si Yourtype (ou de toute classe dérivée de celle-ci) remplace égale et gethascode Vous voudrez peut-être donner un comparateur d'égalité personnalisé au foovalues magasin de données. Le dictionnaire <,> n'est pas du thread-coffre-fort, donc si le parallélisme est nécessaire, utilisez une autre collection ou utilisez des serrures.

C'est probablement un problème que chaque instance "étendue" comme cela ne jamais être des ordures collectées. Vous pouvez plutôt essayer d'utiliser des références faibles à la place, d'une manière ou d'une autre. Voir le commentaire de Svick ci-dessous.


6 commentaires

Je pense que le plus gros problème avec ceci est qu'il fuit la mémoire, chaque fois que vous définissez quelque chose, la valeur sera stockée pour toujours, même après que le parent serait normalement flanc (sauf si vous ne l'exactez pas explicitement). Conditionnalweaktable pourrait aider avec cela.


Oui, je suis venu à penser cela aussi.


@svick je ne connaissais pas cette classe, conditionnellement conditionnel <,> . C'est exactement ce dont nous avons besoin ici! Nous devrions mettre notre int dans un conteneur class mutableut32 {Int Public int Value; } , semble-t-il. Ensuite, nous pourrions utiliser conditionnellement conditionnel .


Moi non plus! Je vais jouer avec un peu de temps et voyez ce que je peux venir avec.


@svick: Je pense que c'est ce que le médecin a commandé.


@Jeppestignielsen: Je pense que nous avons frappé sur la tête. Merci à vous et à Svick et à Tormod en particulier.