2009-06-10 9 views
1

Je suis actuellement en train de réfléchir à une idée que je ne peux pas comprendre.Problème d'instanciation de variable capturée

Le problème est que je veux utiliser une fonction lambda pour instancier une variable capturée et un autre lambda pour accéder à une propriété de cette variable. Puisque l'instanciation se produit dans le lambda, la variable n'est pas réellement instanciée au moment où je veux l'utiliser dans le second lambda. C'est un problème de poule et d'oeuf.

Je sais que la variable sera instanciée le temps qu'elle est utilisée dans le second lambda mais pas le compilateur.

Est-ce que mon idée pourrait fonctionner? Voici le code actuel:

class Program 
{ 
    static void Main(string[] args) 
    { 
     SqlCommand cmd; 

     using (new DisposableComposite(
      () => cmd = new SqlCommand(), 
      () => cmd.Connection)) // <- compiler error - variable not instantiated 
     { 
      // code 
     } 
    } 
} 

class DisposableComposite : IDisposable 
{ 
    private List<IDisposable> _disposables = new List<IDisposable>(); 

    public DisposableComposite(params Func<IDisposable>[] disposableFuncs) 
    { 
     // ensure the code is actually executed 
     foreach (var func in disposableFuncs) 
     { 
      IDisposable obj = func.Invoke(); 
      _disposables.Add(obj); 
     } 
    } 

    public void Dispose() 
    { 
     foreach (var disposable in _disposables) 
     { 
      disposable.Dispose(); 
     } 
    } 
} 

Répondre

5

Voulez-vous dire simplement ajouter:

SqlCommand cmd = null; 

(qui permet de résoudre le petit problème "d'affectation définitive", il est certainement affecté ... un null ;-P Nous puis mettez à jour la valeur avant de l'utiliser).

OMI, bien que, vous feriez mieux avec imbriqués using déclarations ... et on ne sait pas (du code) où la connexion réelle va venir de ...

using(var conn = new SqlConnection(...)) 
using(var cmd = conn.CreateCommand()) { 
    // ... 
} 
+2

Damn .. c'était facile. Je suppose que j'ai besoin d'un autre café. :) – VVS

2

Vous pouvez seulement éviter ceci en mettant cmd à null avant le bloc using:

SqlCommand cmd=null; 

    using (new DisposableComposite(
     () => cmd = new SqlCommand(), 
     () => cmd.Connection)) // <- compiler error - variable not instantiated 
    { 
     // code 
    } 
+0

... mais cela ne mènera-t-il pas à cmd.Connection en lançant une exception NullReferenceException? Ce délégué Func va-t-il "voir" la variable cmd instanciée? –

+0

Il ne lancera pas d'exception, car l'affectation dans le premier délégué aura lieu en premier. Le délégué verra la variable à cause des "fermetures", mais c'est quelque chose qui ne peut pas être expliqué dans un court commentaire :) –

+0

@Fredrik: Voici la définition d'une variable externe capturée: http: //en.csharp-online. net/ECMA-334: _14.5.15.3.1_Captured_outer_variables – VVS

0

D'accord avec Marc que ceci ne se sent pas vraiment bien.

Une autre option consisterait à définir un nouvel objet de type Context, qui sur Dispose dispose tous les objets qu'il fournit.

Par exemple.

using (var ctx = GetContext()) { 
    var cmd = ctx.CreateCommand(); 
    cmd.Connection = ctx.CreateConnection(); 
} 
// cmd is Disposed 
// cmd.Connection is Disposed 
+0

Ouais .. ce code a été inspiré par une autre question (http://stackoverflow.com/questions/966086/using-various-types-in-a-using-statement-c/) et j'étais juste en train de jouer et de chercher un meilleur moyen. Je ne dis pas que c'est en fait un meilleur moyen. – VVS

Questions connexes