1
votes

Appel d'un constructeur de base avec deux arguments dérivés d'un seul argument

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?


2 commentaires

Comment le keyValuePair est-il délimité dans la chaîne? Vous pouvez utiliser string.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?


3 Réponses :


1
votes

Je peux penser à 2 approches distinctes, mais pas des solutions catégoriques:

  1. Vous pouvez mettre en cache le résultat de l'analyse de la paire clé / valeur, afin que le deuxième appel ne soit pas coûteux
  2. Vous pouvez utiliser un modèle de relation has-a plutôt que is-a. Pour que la classe de base ne soit pas dérivée, mais un objet contenu, enveloppé et exposé par la même interface.

J'espère que cela vous aidera.


1 commentaires

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.



1
votes

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);
    }    
}


1 commentaires

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!



1
votes

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);
    }    
}


0 commentaires