8
votes

C # Liste - Toute façon de stocker des classes héritées dans, aussi?

J'essaie de créer un "inventaire" simple d'articles, un peu comme dans n'importe quel RPG. J'ai les classes faits, qui ont des propriétés.

De toute façon, j'ai une classe de base de élément et héritage de celui-ci est arme . élément a des propriétés (nom, valeur, poids, "élément important") également utilisé dans arme , mais arme a des propriétés supplémentaires (attaque , défense, vitesse, rendement).

J'ai le code suivant (désolé si la lisibilité est horrible): xxx

essentiellement, ce que je 'M Essayer de faire est d'ajouter une nouvelle arme à l'inventaire, mais l'inventaire est une liste type. Je suis allé sur un caprice en espérant que, en raison de son héritage, il serait accepté. C'était, mais les propriétés spécifiques à arme n'ont pas accès à:

('shopsystem.item' ne contient pas de définition pour "ATK" et Aucune méthode d'extension 'ATK' Accepter un premier argument de type 'Shopsystem.item' pourrait être trouvé)

Alors, y a-t-il un moyen de réaliser ce que j'avais l'intention de réaliser ici? Avoir un "inventaire" qui peut stocker des objets objet , ainsi que arme , armure , accessoire etc. objets , qui hérit de article ? Il convient également de mentionner que je peux accéder à toutes les propriétés souhaitées si je déclare les suivantes: xxx

Merci beaucoup de lecture.

Voici le < Code> item et arme classes, si quelqu'un est intéressé: xxx


0 commentaires

5 Réponses :


7
votes

Afin d'accéder aux propriétés spécifiques à la classe héritée, vous devez vous lancer sur le type de classe de béton approprié. Donc plutôt que d'accéder à inventaire [0] , vous devez accéder à l'inventaire (arme) [0] .

aussi, si vous effectuez des tâches communes qui auront des tâches communes qui auront Différentes implémentations basées sur la classe sous-jacente, telle que la journalisation des valeurs à la console (que je réalise a été effectuée pour tester, mais est un bon exemple de toute façon), vous devez mettre en œuvre une méthode ultérieure dans la classe de base.

Par exemple, dans la classe de base: xxx

et dans la classe d'armes: xxx

alors, pour accéder à ceci : xxx


5 commentaires

Si j'utilise (arme) inventaire [0] .atk , je reçois toujours le même message d'erreur.


Essayez d'utiliser (arme) inventaire [0]). ATK à la place


Excellent! S'il vous plaît voir ma réponse mise à jour pour une suggestion supplémentaire.


L'utilisation d'une distribution statique échouera sur des éléments qui types d'objets autres que l'arme. Un InvalidCastException sera lancé. Il peut être préférable d'utiliser une distribution dynamique.


Merci, @competent_tech! Je vais avoir besoin d'une méthode comme celle pour le débogage, de sorte que cela facilitera beaucoup les propriétés. @Monrothomes Donc, il serait préférable d'utiliser une distribution dynamique si je ne savais pas quel type serait, par exemple, l'inventaire [3]? Ce serait un contexte plus probable lorsque ce système est opérationnel.



0
votes

Vous pouvez implémenter une interface commune (par exemple, iITEM ) à travers laquelle vous interrogez des propriétés des éléments ou de mettre en œuvre une classe de base commune, probablement un abstrait et utilisez-le comme le type T de la liste . Si vous utilisez cette dernière option, assurez-vous de remplacer les fonctions de la classe de base, le cas échéant, le polymorphisme fera le reste.


0 commentaires

0
votes

Vous devrez jeter la valeur à un arme code> afin d'accéder à ces propriétés, c'est-à-dire l'inventaire ((arme) [0]). ATK) code>. Notez les parenthèses: la coulée a une déficience inférieure à celle de l'accès au champ, vous ne pouvez donc pas écrire (arme) inventaire [0] .atk code>; qui serait interprété comme (arme) (inventaire [0] .atk) code>.

Vous devez également distinguer entre les différentes classes (par exemple, vous avez probablement aussi un armure code> classe). Le plus simple à faire serait d'ajouter une valeur supplémentaire sur la classe de base élément code> qui vous indique le type réel de l'objet, puis de jeter en conséquence. P>

Cependant, un meilleur approche serait d'utiliser l'héritage - let élément code> Définir une série de méthodes pouvant gérer toutes les trucs génériques - par exemple Affichage des informations sur l'article - puis la remplacer dans les classes héritantes. C'est-à-dire au lieu d'accéder directement à toutes ces données, vous appelez à une méthode qui le combine de manière raisonnable. Pour votre exemple particulier, vous convertissez l'élément en une chaîne. Il serait donc logique de remplacer la radiographie () - cela signifie que vous pourrez le faire: P>

public string ToString() {
  //Put all of the data in here, like in your example
  return String.Format("Name: {0}\n...", name, ...);
}


3 commentaires

J'aime cette méthode de totring. Cependant, si je voulais accéder à une seule de ces propriétés (disons, la propriété .ATK) à utiliser dans une formule mathématique? Serait-il préférable de garder la façon dont il est i.e. ((arme) inventaire [0]). ATK ? La chaîne que je faisait était simplement de tester que les valeurs stockaient correctement.


@Deadrust: Oui, vous pouvez le faire et vous pouvez également faire arme usagon useappon = (arme) inventaire [0]; , puis accédez à toutes les propriétés de l'utilitaire sans couplage supplémentaire. Vous voudrez probablement le faire, même plus tôt, par exemple. Stockage de l'arme actuellement équipée sur un lecteur ou unité , mais les RPGS varient de leur approche à cette approche.


Gardez également à l'esprit que vous ne avez-vous d'utiliser Tostring pour cet exemple. Cela peut faire autant de sens de définir votre propre méthode et d'appeler cela - tout dépend de ce que vous avez l'intention de faire avec vos cours.



2
votes

Vous faites la bonne chose en utilisant une liste <élément> pour stocker des éléments et des sous-classes d'articles!

Lorsque vous extrayez l'élément de la liste, il vous suffit de faire un peu de travail pour tester s'il s'agit d'une arme ou d'un autre type d'élément . < / p>

pour voir si l'élément en position i sur la matrice est un arme , utilisez l'opérateur comme , qui reviendra null si l'élément n'est pas le type spécifié (peut-être qu'il s'agit d'une armure ou d'un autre type d'élément). Ceci est connu sous le nom de dynamique coulée. Ça fonctionne même si l'élément est null . xxx

Une autre façon de le faire consiste à vérifier le type à l'aide du est Opérateur avant de faire un statique couler. xxx


3 commentaires

Meilleure alternative au deuxième test: si (inventaire [i] est arme) . Mais votre premier exemple (avec comme ) est probablement préférable de toute façon, car il évite de casser l'objet deux fois. :)


@Danj Yep, merci! Cela évite également la nécessité de la vérification nulle. Réponse ajustée en conséquence. :)


Ce premier exemple est exactement ce que j'aurai besoin de suffisamment, lorsque je commence à ajouter de manière dynamique des éléments à l'instance inventaire . Merci beaucoup!



1
votes

C'est là que Linq peut être votre ami lorsque vous traitez du polymorphisme. Le problème avec les éléments de casting est lorsque l'index indiqué n'est pas le type correct. (Ie inventaire [0] n'est pas un arme , (arme) inventaire [0] va jeter.)

Vous pouvez éviter L'exception en utilisant: xxx

Cependant, vous allez faire des chèques #null partout. Utilisation de LINQ Vous obtenez beaucoup de flexibilité: xxx

à partir d'ici, vous pouvez utiliser , sRevarefault , etc. Recherchez des données qui vous intéressent ou iTERE sur les armes.


1 commentaires

+1 Ce serait mon approche, il limite à quel point votre code doit être conscient de l'inventaire générique. Par exemple, vous pouvez écrire une méthode qui agit sur une liste list et passe inventaire.oftype () dans elle. Cette méthode n'a jamais besoin de s'inquiéter de l'existence d'autres types d'articles dans votre inventaire.