2009-12-28 10 views
3

Je me suis heurté à un problème de conception facile à résoudre mais que je n'ai pas encore rencontré dans ma jeune vie.Délégué appelant dans un constructeur

J'ai une classe qui doit passer par quelques procédures d'installation avant que quoi que ce soit d'autre ne se produise.

Cependant, lors de la construction de cette classe, j'ai dans les paramètres du constructeur un délégué qui peut être passé pour que l'utilisateur puisse ajouter ses propres informations à la classe. Lorsque cette option est appelée, l'étendue qui crée la classe n'a toujours pas d'instance valide et, par conséquent, une erreur d'exception nulle se produit.

Comment puis-je concevoir autour de cela? Devrais-je transmettre une instance de "this" à ce délégué?

Quelle est une bonne décision à prendre ici? J'ai une méthode "StartServices()" où je pourrais facilement mettre l'appel au délégué mais je pense que le design devrait être dans le constructeur.

Merci pour le conseil!

+1

S'il vous plaît ajouter votre code, à cette heure tardive, il est difficile de le visualiser :) –

+0

Pourquoi vous ne pouvez pas simplement appeler des méthodes de classe pour ajouter cette information supplémentaire juste après la création d'une classe? Puisque vous passez un délégué, vous savez sans doute quelles informations devraient être ajoutées au moment de la création. – vava

+0

@ bobber205 - re votre commentaire, il obéit aux règles d'accessibilité normales, ce qui signifie qu'il * peut * accéder privé/protected/interne etc * dans les bonnes circonstances *. –

Répondre

6

On dirait que vous voulez passer un Action<T> (ou similaire), de sorte que, à ne importe quel point la classe veut le délégué, il peut appeler theDelegate(this); par exemple:

var instance = new SomeType(..., obj => { /* extra code invovling obj */ }); 

Alors obj sera l'instance lors de sa création, et il a l'avantage que la méthode généré par le compilateur ne nécessite aucun état/capture (sauf si vous avez besoin que vous-même).

Cependant! Je serais prudent d'appeler un délégué à l'intérieur un constructeur, pour la même raison que virtual doit être traitée avec prudence - dans un modèle d'objet profond la classe entière peut ne pas être entièrement créée au point votre constructeur de niveau intermédiaire (qui invoque le méthode delegate ou overridden) se déclenche, fournissant un accès douteux à un objet dans un état incomplet.

+0

Le délégué peut uniquement accéder aux méthodes publiques de la classe. Merci pour l'info! – bobber205

4

Pensez à utiliser un factory method:

public class MyClass 
{ 
    private MyClass() {} 

    public static MyClass Create(delegate d ...) 
    { 
     var instance = new MyClass(); 
     d.(instance); 
     return instance; 
    } 
} 

utiliser alors comme ceci:

var o = MyClass.Create(...); 

Vous pouvez aussi aller avec une classe d'usine:

var o = factory.CreateMyClass(...); 
2

Fondamentalement, cela ressemble le code que vous voulez ne devrait pas être du tout dans le constructeur. Le constructeur est ce qui crée l'objet. Jusqu'à ce qu'il se termine, l'objet n'est pas garanti pour "fonctionner correctement". Maintenant, il peut travail et oui, vous pouvez obtenir le ce pointeur, mais le code appelant s'attendrait à être entièrement construit. Donc, du point de vue de la conception, ce n'est pas une bonne pratique. Juste une autre méthode qui est appelée après le constructeur (avec une interface si cela aiderait votre polymorphisme).

0

Cette approche semble étrange, quel type de travail d'installation est effectué via les délégués?

La levée d'un événement à la fin du constructeur serait peut-être un peu plus standard.

3

Je recommande de ne pas utiliser de délégué dans un constructeur. Le délégué pourrait facilement accéder aux données sur d'autres threads, provoquant plusieurs effets secondaires non évidents. Vous devez scinder la création de classe et l'initialisation de classe dans ce cas.

Utilisation du Factory pattern vous aidera à la responsabilité proprement séparée pour la création d'objets complexes , mais aucune initialisation d'objet . Je considère l'injection de comportement dans un constructeur comme un anti-pattern.

Une solution à votre problème peut être l'injection de comportement en tant que (objet) dépendances avec des interfaces bien définies. Votre souhait de faire passer un délégué dans le constroctur est un signe d'une mauvaise séparation des préoccupations et de la violation du SingelResponsibilityPrinciple.