J'ai une classe de base qui prend deux arguments dans son constructeur:
public class DerivedClass : BaseClass { public DerivedClass (string keyValuePair) : BaseClass( SomethingExpensive(keyValuePair, out object _value), _value) { } private static string SomethingExpensive(string input, out object value) { // Do expensive things value = derivedValue; return derivedKey; } }
Ma classe dérivée est construite différemment, en utilisant un seul argument complexe que je peux ensuite diviser en arguments de classe de base.
public class DerivedClass : BaseClass { public DerivedClass (string keyValuePair) : BaseClass( SomethingExpensive(keyValuePair).Key, SomethingExpensive(keyValuePair).Value) { } private static KeyValuePair<string,object> SomethingExpensive(string input) { // Do expensive things return new KeyValuePair<string,object>(derivedKey, derivedValue); } }
Étant donné que je n'ai aucun contrôle sur BaseClass
et que je ne peux pas lui donner un nouveau constructeur, j'essaie de trouver un moyen de passer avec ces arguments sans appeler SomethingExpensive
deux fois.
J'ai pensé à utiliser un paramètre out
pour générer un nouvel identifiant pour les arguments de constructeur supplémentaires pendant le premier appel:
public class BaseClass { public BaseClass(string key, object value) { ... } }
Mais cela est rejeté dans le cadre actuel avec l'erreur:
Erreur CS8107 La fonctionnalité «déclaration des variables d'expression dans les initialiseurs et requêtes de membre» n'est pas disponible dans C # 7.0. Veuillez utiliser la version 7.3 ou supérieure.
Des idées alternatives?
3 Réponses :
Je peux penser à 2 approches distinctes, mais pas des solutions catégoriques:
J'espère que cela vous aidera.
Bonnes suggestions merci. "is-a" est définitivement requis dans mon cas particulier (par exemple, je ne veux pas avoir à réimplémenter toutes les interfaces de classe de base en tant que pass-through) mais l'approche de mise en cache est pratique, sinon élégante.
Ajoutez simplement une classe d'adaptateur entre BaseClass
et DerivedClass
public class BaseClass { public BaseClass(string key, object value) { ... } } public class AdapterClass : BaseClass { public AdapterClass (SomethingExpensive se) : BaseClass(se.key, se.value) { ... } } public class DerivedClass : AdapterClass{ public DerivedClass (string keyValuePair) : AdapterClass(SomethingExpensive(keyValuePair)) { } private static KeyValuePair<string,object> SomethingExpensive(string input) { // Do expensive things return new KeyValuePair<string,object>(derivedKey, derivedValue); } }
Merci pour la pensée. Nous pouvons en fait éviter complètement le besoin d'une classe intermédiaire simplement en ayant un deuxième constructeur privé dans la DerivedClass
. Je n'y aurais pas pensé sans cette suggestion, alors merci!
Inspiré de la solution de @ alex, mais sans avoir besoin d'une classe supplémentaire:
public class DerivedClass : BaseClass { public DerivedClass (string keyValuePair) : this(SomethingExpensive(keyValuePair)) { } private DerivedClass (Tuple<string,object> arguments) : BaseClass(arguments.Item1, arguments.Item2) private static Tuple<string,object> SomethingExpensive(string input) { // Do expensive things return Tuple.Create(derivedKey, derivedValue); } }
Comment le
keyValuePair
est-il délimité dans la chaîne? Vous pouvez utiliserstring.Split ()
pour obtenir la clé et la valeur et les transmettre au constructeur de base.@LewsTherin - Si cela aide avec l'analogie, imaginez que
keyValuePair
est une chaîne fortement chiffrée qui contient"key: value"
une fois déchiffrée, mais prend environ 10 secondes à déchiffrer. Pouvez-vous proposer une approche pour appeler le constructeur de base en 10 secondes au lieu de 20 secondes?