Supposons que j'ai une classe abstrait générique qui fournit une fonctionnalité de constructeur par défaut afin de ne pas avoir à répéter le code dans vos classes héritées: maintenant le problème est que lorsque j'écris quand j'écris Deux classes héritées comme: p> Comme vous pouvez le constater que ces deux sont vraiment des énumérations de type-sécurité. Ils ne fournissent que des valeurs prédéfinies et elles ne peuvent pas être instanciées à d'autres fins. P> Le problème est que ces deux classes héritées utilisent les mêmes types génériques avec la classe de base qui est dans mon cas, la combinaison est changeant champ De statique à l'instance ne fonctionnera pas, car ils me retrouverai avec 4 instances qui détiennent une seule valeur ... p> p> Question H2>
base
String, String Code> C'est pourquoi il n'y a que
5 Réponses :
Cela fonctionnera. Je crois que c'est connu comme le modèle de modèle curieusement récurrent, mais ne me cite pas sur ce la partie "curieuse" est que les définitions de un code> et < Code> Deux code> sont autorisés à se servir de paramètres de type à eux-mêmes! P> P>
Il s'appuie sur des personnes spécifiant le code> correctement, cependant.
Oui, c'est un piratage, mais il est important de noter qu'il n'applique rien .
@ROBERT: Quelle boucle parlez-vous?
@Groo: Celui-ci: Base
@Groo: Très bon lien! En fait, je parlais de la même boucle infinie qui est mentionnée dans l'article en tant que référence circulaire. Je n'ai pas pu me cacher la tête. :)
rendre votre base diffère.
public abstract class Base<T, TKey, TValue> where T : Base<T, TKey, TValue> { private static readonly IDictionary<TKey, T> Values = new Dictionary<TKey, T>(); public TKey Key { get; private set; } public TValue Value { get; private set; } protected Base(TKey key, TValue value) { this.Key = key; this.Value = value; Values.Add(key, (T)this); } }
Merci kris. Je vais vous remettre, parce que je ne sais pas non plus pourquoi cela a été évité. Surtout parce que vous avez simplifié la définition de dictionnaire. Il enregistre t code> instances ... donc +1 de moi.
Hmmm. Mais si vous utilisez un identificateur
valeurs.add (touche, ceci) code> ...
En effet, ça m'a raté. Eh bien, dans ce cas, nous devons changer la définition du dictionnaire. Je garderais toujours la contrainte cependant. Je vais mettre à jour la réponse, bien que je puisse la supprimer car il est maintenant très proche de l'autre.
Pas vraiment .. Depuis que je vais ajouter des instances, il est prudent de la modifier à: valeurs.add (clé, ceci comme t) code>. Et il fonctionne.
True encore, sauf pour l'opérateur comme code>; J'utiliserais une distribution explicite.
Le problème, bien sûr, se pose car vos deux classes partagent la même classe de base avec les mêmes arguments de type générique. Cela signifie qu'ils partagent les mêmes membres statiques.
Comment puis-je remédier à ce problème et séparer ceux-ci tout en conservant cette fonctionnalité sur la classe de base, donc je ne répète pas mon code? P> blockQuote>
Une approche serait de créer votre dictionnaire dans un dictionnaire basé sur le type d'exécution actuel: p>
xxx pré> Ceci fait que toutes les recherches soient 2 phases, Comme vous devez rechercher le type actuel puis em> la valeur de ce dictionnaire, mais il ne s'appuie pas sur la modification de votre API de sous-classe. P> P>
+1 C'est ce que je voulais mentionner. En réalité, ce dictionnaire statique peut faire partie d'une classe générique complètement différente avec le type de classes héritées en tant que paramètre.
Il convient de noter que cela constituerait toujours un dictionnaire statique par type générique résolu, il suffit de saisir différemment.
@AdamHouldsworthhorth Oui - Bien que maintenant, il est clément à la sous-classe, de sorte que vous obtiendrez "efficacement" ce que l'OP veut. C'est un hack, mais il répond directement à la question de l'OP
@Reedcopsey Oui, je suis d'accord, je clarifiais simplement la différence entre cela et l'autre réponse qui entraînerait deux variables statiques car les types génériques résolvent différemment.
Je pensais à la mettre en œuvre aussi, mais au lieu d'avoir des dictionnaires imbriqués, je concaténate Type avec la clé, car j'utilise des cordes comme des clés ...
@ROBERTKORITNIK Votre hiérarchie de classe suggère d'autres choses peuvent être des clés, cependant. Si ce n'est pas le cas, vous pouvez simplifier cela dramatiquement ...
@REEDCOPSEY: Ils sont, mais depuis que j'étais coincé et pour le moment où mes clés ne seraient que des cordes, je m'amusais avec l'idée ... mais dans la réalité, ces clés peuvent réellement être n'importe quel type que commutateur code> La déclaration peut mâcher ... La documentation dit qu'il peut être l'une des opérations suivantes: Sbyte, octet, court, Ushort, Int, Uint, Long, Ulong, Char, String ou un Enum-Type B>. Mais je ne peux pas faire de contrainte à ce sujet, car il s'agit d'un mélange de valeurs et de types de référence ... La chose est que j'ai réussi à écrire une classe abstraite de base pour les énumérations C # Safe-Safe avec la coulée explicite et la conversion intégrale implicite.
@RobertKoritnik Alors ouais, la fixant à une chaîne n'est probablement pas aussi élégante que de lui permettre d'être n'importe quoi. Avec plus d'informations sur ce que vous faites, il peut y avoir une meilleure approche, bien que
Je vais tout mettre dans un Publication du blog plus tard de toute façon. D'autres développeurs peuvent également trouver utile.
@REEDCOPSEY: Qu'est-ce que je fais? B> J'ai écrit une classe de base enum de type-Safe enum, c'est-à-dire Classe abstraite Public Typeafeenum
TVALUE < / code> est le type de sous-couche qui ne se limite pas aux types intégraux tels que
Enum code> est. Et
TNAME code> est le type pour les membres de l'énumération. Habituellement, une chaîne code> code>, mais ne leur est pas limitée. Peut être n'importe quoi,
DateTime code>, objets prédéfinis ... Tout ce dont vous avez besoin. Si vous utilisez des types hérités dans les instructions code> commutateurs code>, alors
TVALUE code> doit être un type intégral, une chaîne ou une énumération.
@ROBERTKORITNIK Si c'est votre objectif entier, pourquoi ne pas simplement utiliser un dictionnaire comme-est? Ceci est juste une couche supplémentaire d'abstraction qui ne vous achète pas beaucoup ...
@Reedcopsey: Pas vraiment parce que j'ai aussi des opérateurs implicites et explicites définis sur le type afin que vous puissiez jeter explicitement sur ces énums et les utiliser directement dans la classe de commutation. Ce qui m'achète, c'est que l'utilisation de ces énumes est identique à des types d'énumération normaux.
Ceci est par conception. Un membre statique n'aura qu'un seul copie dans toutes les instances et un membre statique d'une classe de base n'aura qu'une copie dans toutes les instances de toutes ses sous-classes. P>
Pourquoi es-tu statique? Voulez-vous réellement que tous les cas de partagent un dictionnaire commun? P>
Si vous voulez que vous soyez partager sur ceux, mais que vous ne partagez pas avec deux, vous devrez changer votre conception. Soit ne le rend pas statique (qui ne causera aucun partage) ou de le rendre statique au niveau de chaque sous-classe. p>
Faire une méthode / une propriété abstraite dans la classe de base et remplacer dans les sous-classes si vous souhaitez garder l'API la même entre eux P>
Cela ne répond pas directement à la question, mais fournit plutôt une conception alternative pour accéder au même objectif. SUB> Il me semble que vous essayez d'utiliser une classe de base pour quelque chose Ce n'est pas le comportement de base, ni au moins de comportement statique. p> Séparez les préoccupations d'être une liste de recherche élément em> et de fournir la référence de la liste de recherche. P> Si vous essayez de fournir des recherches connues, je ferais la référence de la liste de recherches séparée des éléments de recherche (comme dans, pas un membre statique): p> Ensuite, chaque type peut simplement pointer sur le dictionnaire correspondant, le nommer et l'accéder via une réflexion ou fournir une fonction de fonctionnement: p> Ceci vous laissera également séparer La liste elle-même des éléments de la liste (via l'injection peut-être). P> Notez également que si les instances de la classe de base conservent une référence aux mêmes dictionnaires, il n'y aura pas besoin d'avoir le membre statique. < / p> p>
C'est pourquoi le champ statique de la classe de base contient 4 valeurs au lieu de chacun des 2 champs statiques portant chacun 2 valeurs. code> attendre, où
: base code> finit-il avec 4 valeurs?
@Jcolebrand: Eh bien, car ils héritent de
base code> et la manière dont les classes génériques et les champs statiques fonctionnent, cela signifie qu'un seul champ statique est créé. Et c'est-à-dire pour la base code>. Toutes les valeurs sont donc sauvegardées, même s'il existe deux classes héritantes.
Même si tu es instanciant une nouvelle chaque fois? Je pensais que la sémantique a indiqué que la statique serait statique sur
deux code> ou statique sur
un code>, pas statique sur
base code>. Je suppose que c'est un vrai problème que vous essayez de surmonter. Pourquoi ne pouvez-vous pas déplacer ceux-ci dans une autre sous-classe qui est une propriété à ce sujet?
@jcolebrand Les 4 éléments proviennent de la construction de deux instances de
deux code> et de deux instances de
un code>,
un code> et
deux code> Les deux regardent les mêmes valeurs code> statiques code>.
@Jcolebrand: Pourquoi n'écrivez-vous pas une réponse et fournissez un certain code, car je suis déjà crosseyed i> à cause de ce problème ... :)