2009-03-25 6 views
3

Pourquoi le premier constructeur de ClassA provoque-t-il l'erreur de compilation "ne peut pas utiliser" ce "in-intializer"?Chaîne de constructeurs avec "this"

... ou comment puis-je faire fonctionner cela?

Merci

public sealed class ClassA : IMethodA 
{ 
    private readonly IMethodA _methodA; 

    public ClassA():this(this) 
    {} 

    public ClassA(IMethodA methodA) 
    { 
     _methodA = methodA; 
    } 

    public void Run(int i) 
    { 
     _methodA.MethodA(i); 
    } 

    public void MethodA(int i) 
    { 
     Console.WriteLine(i.ToString()); 
    } 
} 

public interface IMethodA 
{ 
    void MethodA(int i); 
} 

Répondre

1

Vous ne pouvez pas utiliser le mot-clé quand this enchaînant les constructeurs essentiellement parce this fait référence à un objet qui n'a pas été encore instanciée (création de l'objet ne commence pas jusqu'à ce que certains (niveau supérieur ou la base) le bloc constructeur a été entré). D'ailleurs, pourquoi voudriez-vous exactement faire cela? Il semble plutôt inutile lorsque vous avez accès au mot-clé this partout.

Je recommande simplement à l'aide des constructeurs indépendants en tant que tels:

public sealed class ClassA : IMethodA 
{ 
    private readonly IMethodA _methodA; 

    public ClassA() 
    { 
     _methodA = this; 
    } 

    public ClassA(IMethodA methodA) 
    { 
     _methodA = methodA; 
    } 
} 

Peut-être que j'ai mal compris ce que vous essayez de faire, mais nous espérons que vous résoudre le problème pour vous.

9

Vous êtes autorisé à utiliser la syntaxe this(...) pour appeler un autre constructeur au même niveau - cependant, vous ne pouvez pas utiliser this (l'instance en cours) dans ce contexte.

L'option la plus simple consiste ici à dupliquer le code d'affectation (_methodA = methodA).

Une autre option pourrait être nul coalescent:

public ClassA():this(null) 
{} 

public ClassA(IMethodA methodA) 
{ // defaults to "this" if null 
    _methodA = methodA ?? this; 
} 
+0

@Marc Gravell: bat-moi dessus ... –

3

Ceci est appelé à l'article 10.11.1 de la C# spec

Une instance constructeur initialiseur ne peut pas accéder à l'instance étant créé . Par conséquent, il est une erreur de compilation pour faire référence à cette dans une expression d'argument de la initialiseur constructeur , comme une erreur de compilation pour une expression arguments pour faire référence à toute instance membre par un simple nom.

Il n'existe aucun moyen de faire fonctionner ceci avec un constructeur d'instance, car il est impossible d'y accéder. Ce que vous pouvez faire est de rendre le constructeur privé, créer une méthode d'initialisation et un constructeur statique.

public sealed class ClassA : IMethodA {  
    private ClassA() { } 
    private void Initialize(IMethodA param) { ... } 
    public static ClassA Create() { 
    var v1 = new ClassA(); 
    v1.Initialize(v1); 
    return v1; 
    } 
    public static ClassA Create(IMethodA param) { 
    var v1 = new ClassA(); 
    v1.Initialize(param); 
    return v1; 
    } 
} 
3

Vous essayez de passer l'objet avant qu'il ne soit construit. Bien que le compilateur puisse faire quelque chose de sensé dans ce cas, en général cela ne fonctionnera pas.

Votre exemple réel fonctionne si vous faites ceci:

public ClassA() 
    { 
    _methodA = this; 
    } 

Mais vous voulez sans doute partager plus logique, donc il suffit d'utiliser une fonction.

public ClassA() 
    { 
    SetStuff(); 
    _methodA = this; 
    } 

    public ClassA(IMethodA methodA) 
    { 
    SetStuff(); 
    _methodA = methodA; 
    } 
+0

Notez que vous pouvez toujours utiliser SetStuff avec des champs readonly ... * si * vous utilisez un argument 'ref' /' out'. Que cela en vaille la peine dépend du scénario. –

Questions connexes