public class MyClass
{
public object Prop1 { get; set; }
public object Prop2 { get; set; }
public object Prop3 { get; set; }
}
Supposons que j'ai un objet myObject
de MyClass
et que je doive réinitialiser ses propriétés, est-il préférable de créer un nouvel objet ou de réaffecter chaque propriété? Supposons que je n'ai aucune utilisation supplémentaire avec l'ancienne instance.
myObject = new MyClass();
ou
myObject.Prop1 = null;
myObject.Prop2 = null;
myObject.Prop3 = null;
c#
object-oriented
construction
Cloches
la source
la source
Suppose I have an object myObject of MyClass and I need to reset its properties
- Si la réinitialisation des propriétés de votre objet est nécessaire ou s'il est utile de modéliser le domaine problématique, pourquoi ne pas créer unereset()
méthode pour MyClass. Voir la réponse de HarrisonPaine ciRéponses:
Instancier un nouvel objet est toujours mieux, alors vous avez 1 place pour initialiser les propriétés (le constructeur) et pouvez facilement le mettre à jour.
Imaginez que vous ajoutez une nouvelle propriété à la classe, vous préférez mettre à jour le constructeur plutôt que d'ajouter une nouvelle méthode qui réinitialise également toutes les propriétés.
Maintenant, il y a des cas où vous voudrez peut-être réutiliser un objet, un cas où une propriété est très coûteuse à réinitialiser et que vous voudriez le conserver. Ce serait cependant plus spécialisé et vous auriez des méthodes spéciales pour réinitialiser toutes les autres propriétés. Vous voudriez toujours créer un nouvel objet parfois même pour cette situation.
la source
myObject = new MyClass(oldObject);
. Bien que cela impliquerait une copie exacte de l'objet d'origine dans une nouvelle instance.new MyClass(oldObject)
c'est la meilleure solution pour les cas où l'initialisation coûte cher.Vous devriez certainement préférer créer un nouvel objet dans la grande majorité des cas. Problèmes de réaffectation de toutes les propriétés:
A
et classeB
sont toutes deux des instances de classe passées,C
elles doivent savoir si elles passeront jamais la même instance, et si oui, si l'autre l'utilise toujours. Cela couple étroitement les classes qui, autrement, n'ont aucune raison d'être.Fraction
classe avec un numérateur et un dénominateur, et que vous vouliez faire en sorte qu'elle soit toujours réduite (c'est-à-dire que le pgcd du numérateur et du dénominateur était 1). C'est impossible à faire si vous voulez permettre aux gens de définir le numérateur et le dénominateur publiquement, car ils peuvent passer par un état invalide pour passer d'un état valide à un autre. Par exemple 1/2 (valide) -> 2/2 (invalide) -> 2/3 (valide).Ce sont tous des problèmes assez importants. Et ce que vous obtenez en échange du travail supplémentaire que vous créez n'est ... rien. La création d'instances d'objets est, en général, incroyablement bon marché, de sorte que les performances seront presque toujours totalement négligeables.
Comme l'autre réponse l'a mentionné, le seul moment où les performances peuvent être une préoccupation pertinente est si votre classe effectue des travaux de construction considérablement coûteux. Mais même dans ce cas, pour que cette technique fonctionne, vous devez être en mesure de séparer la partie coûteuse des propriétés que vous réinitialisez, afin que vous puissiez utiliser le modèle de poids de mouche ou similaire à la place.
En guise de remarque, certains des problèmes ci-dessus pourraient être quelque peu atténués en n'utilisant pas de setters et en ayant à la place une
public Reset
méthode sur votre classe qui prend les mêmes paramètres que le constructeur. Si, pour une raison quelconque, vous vouliez emprunter cette voie de réinitialisation, ce serait probablement une bien meilleure façon de le faire.Pourtant, la complexité et la répétition supplémentaires qui s'ajoutent, ainsi que les points ci-dessus qu'il ne traite pas, sont toujours un argument très convaincant contre le faire, surtout lorsqu'il est comparé aux avantages inexistants.
la source
Étant donné l'exemple très générique, c'est difficile à dire. Si "réinitialiser les propriétés" a un sens sémantique dans le cas du domaine, il sera plus logique pour le consommateur de votre classe d'appeler
Que
Je n'exigerais JAMAIS de faire appel au consommateur de votre classe
Si la classe représente quelque chose qui peut être réinitialisé, elle doit exposer cette fonctionnalité via une
Reset()
méthode, plutôt que de s'appuyer sur l'appel du constructeur ou de définir manuellement ses propriétés.la source
Comme le suggèrent Harrison Paine et Brandin, je réutiliserais le même objet et factoriserais l'initialisation des propriétés dans une méthode Reset:
la source
Si le modèle d'utilisation prévu pour une classe est qu'un seul propriétaire conservera une référence à chaque instance, aucun autre code ne conservera de copie des références, et il sera très courant pour les propriétaires d'avoir des boucles qui doivent, souvent , " remplissez "une instance vide, utilisez-la temporairement et n'en aurez plus jamais besoin (une classe commune répondant à un tel critère serait
StringBuilder
), alors il peut être utile du point de vue des performances pour la classe d'inclure une méthode pour réinitialiser une instance à aimer- nouvelle condition. Une telle optimisation ne vaut probablement pas grand-chose si l'alternative ne nécessite que la création de quelques centaines d'instances, mais le coût de création de millions ou de milliards d'instances d'objets peut s'additionner.Sur une note connexe, il existe quelques modèles qui peuvent être utilisés pour les méthodes qui doivent retourner des données dans un objet:
La méthode crée un nouvel objet; renvoie la référence.
La méthode accepte une référence à un objet mutable et la remplit.
La méthode accepte une variable de type référence en tant que
ref
paramètre et utilise l'objet existant si approprié, ou modifie la variable pour identifier un nouvel objet.La première approche est souvent la plus simple sémantiquement. Le second est un peu gênant du côté appelant, mais peut offrir de meilleures performances si un appelant est souvent capable de créer un objet et de l'utiliser des milliers de fois. La troisième approche est un peu maladroite sur le plan sémantique, mais peut être utile si une méthode doit renvoyer des données dans un tableau et que l'appelant ne connaîtra pas la taille de tableau requise. Si le code appelant contient la seule référence au tableau, réécrire cette référence avec une référence à un tableau plus grand équivaudra sémantiquement à simplement agrandir le tableau (ce qui est le comportement souhaité sémantiquement). Bien que l'utilisation
List<T>
puisse être plus agréable que l'utilisation d'un tableau redimensionné manuellement dans de nombreux cas, les tableaux de structures offrent une meilleure sémantique et de meilleures performances que les listes de structures.la source
Je pense que la plupart des gens qui répondent à l'idée de favoriser la création d'un nouvel objet n'ont pas de scénario critique: la collecte des ordures (GC). GC peut avoir un réel impact sur les performances dans les applications qui créent beaucoup d'objets (jeux de réflexion ou applications scientifiques).
Disons que j'ai un arbre d'expression qui représente une expression mathématique, où les nœuds internes sont des nœuds de fonction (ADD, SUB, MUL, DIV) et les nœuds de feuille sont des nœuds terminaux (X, e, PI). Si ma classe de nœuds a une méthode Evaluate (), elle fera probablement appel de manière récursive aux enfants et collectera des données via un nœud de données. À tout le moins, tous les nœuds terminaux devront créer un objet Data, puis ceux-ci pourront être réutilisés en remontant dans l'arbre jusqu'à ce que la valeur finale soit évaluée.
Supposons maintenant que j'ai des milliers de ces arbres et que je les ai évalués en boucle. Tous ces objets de données vont déclencher un GC et provoquer un impact sur les performances, un gros (jusqu'à 40% de perte d'utilisation du processeur pour certaines exécutions dans mon application - j'ai exécuté un profileur pour obtenir les données).
Une solution possible? Réutilisez ces objets de données et appelez simplement certains .Reset () sur eux après avoir fini de les utiliser. Les nœuds terminaux n'appelleront plus 'new Data ()', ils appelleront une méthode Factory qui gère le cycle de vie de l'objet.
Je le sais parce que j'ai une application qui a rencontré ce problème et qui l'a résolu.
la source