2010-11-23 16 views
0

Désolé pour beaucoup de code à lire. C'est le moyen le plus simple de montrer le problème.Exception de constructeur de sous-classe quitte l'instance de la classe parente

using System; 
using System.Collections.Generic; 

namespace P1 
{ 
    class A 
    { 
     static Dictionary<int, A> a = new Dictionary<int, A>(); 
     static int i = 0; 

     int id; 
     public A() 
     { 
      id = ++i; 
      a[id] = this; 
     } 

     public static int Count() { return a.Count; } 
    } 

    class B : A 
    { 
     public B() 
     { 
      throw new Exception(); 
     } 
    } 

    class Program 
    { 
     static void Main(string[] args) 
     { 
      try 
      { 
       var b = new B(); 
      } 
      catch 
      { 
       // What should be here ???? 
      } 

      Console.WriteLine(A.Count()); //prints 1 - not good 
      Console.ReadKey(); 
     } 
    } 
} 

Quelqu'un peut-il suggérer une logique de nettoyage pour le cas où le constructeur de sous-classe échoue?

+0

Cela dépend. Votre programme peut-il récupérer d'une manière ou d'une autre si le constructeur de 'B' échoue? Pourquoi "1" "n'est pas bon"? –

+0

Même si b échoue, l'instance d'un reste, et je ne sais pas comment l'enlever. – Marko

+0

@Marko: si vous souhaitez séparer le souci de la création d'objet du souci d'insertion d'objet dans le dictionnaire, alors cette question ne se posera pas. –

Répondre

1

Vous devez placer la logique de nettoyage dans le constructeur de B, car vous ne pouvez pas accéder à la référence d'instance après l'échec du constructeur.

Voici un exemple sur la façon dont vous pourriez faire ceci:

class A 
{ 
    static Dictionary<int, A> a = new Dictionary<int, A>(); 
    static int i = 0; 

    int id; 
    public A() 
    { 
     id = ++i; 
     a[id] = this; 
    } 

    protected void Destroy() 
    { 
     a.Remove(id); 
     i--; 
    } 

    public static int Count() { return a.Count; } 
} 

class B : A 
{ 
    public B() 
    { 
     try 
     { 
      throw new Exception(); 
     } 
     catch (Exception) 
     { 
      Destroy(); 
      throw; 
     } 
    } 
} 
+0

Comment faire cela? – Marko

+0

Notez que cela ne fonctionnera pas si vous dites 'x = new B(); y = nouveau B(); x = null; GC.Collect(); x = new B(); 'Si vous faites cela, vous aurez 2 A avec l'ID 2, et seulement 1 d'entre eux sera dans le dictionnaire. C'est supposer que la création de l'objet de la sous-classe est toujours réussie. – Kendrick

+0

Intéressant ... mais pas assez bon pour moi car j'ai beaucoup de types de sous-classes :( – Marko

0

Votre constructeur de la classe de base est appelée avant que l'exception est levée, de sorte que l'objet a déjà été créé et qui lui est attribué est place dans a. Si vous souhaitez que l'objet ne soit pas créé par le constructeur, vous pouvez envisager une méthode statique pour instancier un nouvel A au lieu d'utiliser le constructeur par défaut. Ensuite, lorsque l'instanciation de l'objet échoue (en B), vous lancerez l'exception avant que l'objet ne soit ajouté au dictionnaire.