2010-08-10 6 views
3

Je suis novice en matière de cours anonymes, et aujourd'hui, je pense avoir rencontré le premier cas où je me sentais vraiment capable de les utiliser. J'écris une méthode qui aurait avantage à stocker des données temporaires à l'intérieur d'une classe, et puisque cette classe n'a aucune signification en dehors de cette méthode, l'utilisation d'une classe anonyme a du sens pour moi (au moins à ce moment-là). Après avoir commencé le codage, il semblait que j'allais devoir faire quelques concessions. J'aime mettre des choses comme des calculs sur des variables temporaires, de sorte que pendant le débogage, je puisse vérifier des bits de calculs à la fois en segments logiques. Ensuite, je veux assigner quelque chose de plus simple à la valeur finale. Cette valeur serait dans la classe anonyme.Classes anonymes, données temporaires et collections de classes anonymes

Le problème est que pour implémenter mon code avec des classes anonymes de manière concise, j'aimerais utiliser LINQ. Le problème ici est que je ne pense pas que vous pouvez faire de tels calculs temporaires à l'intérieur de la déclaration. ou pouvez-vous?

Voici un exemple de ce que je artificiel veux faire:

namespace AnonymousClassTest 
{ 
    /// <summary> 
    /// Interaction logic for Window1.xaml 
    /// </summary> 
    public partial class Window1 : Window 
    { 
     ObservableCollection<RectanglePoints> Points { get; set; } 

     public class RectanglePoints 
     { 
      public Point UL { get; set; } 
      public Point UR { get; set; } 
      public Point LL { get; set; } 
      public Point LR { get; set; } 
     } 

     public class DontWantThis 
     { 
      public double Width { get; set; } 
      public double Height { get; set; } 
     } 

     private Dictionary<string,string> properties = new Dictionary<string,string>(); 
     private Dictionary<string,double> scaling_factors = new Dictionary<string,double>(); 

     private void Sample() 
     { 
      // not possible to do temp variables, so need to have 
      // longer, more unreadable assignments 
      var widths_and_heights = from rp in Points 
            select new 
            { 
             Width = (rp.UR.X - rp.UL.X) * scaling_factors[properties["dummy"]], 
             Height = (rp.LL.Y - rp.UL.Y) * scaling_factors[properties["yummy"]] 
            }; 

      // or do it in a for loop -- but then you have to use a concrete 
      // class to deal with the Width and Height storage 
      List<DontWantThis> other_widths_and_heights = new List<DontWantThis>(); 
      foreach(RectanglePoints rp in Points) { 
       double base_width = rp.UR.X - rp.UL.X; 
       double width_scaling_factor = scaling_factors[properties["dummy"]]; 
       double base_height = rp.LL.Y - rp.UL.Y; 
       double height_scaling_factor = scaling_factors[properties["yummy"]]; 

       other_widths_and_heights.Add(new DontWantThis 
               { 
                Width=base_width * width_scaling_factor, 
                Height=base_height * height_scaling_factor 
               }); 
      } 

      // now we want to use the anonymous class, or concrete class, in the same function 
      foreach(var wah in widths_and_heights) 
       Console.WriteLine(String.Format("{0} {1}", wah.Width, wah.Height)); 
      foreach(DontWantThis dwt in other_widths_and_heights) 
       Console.WriteLine(String.Format("{0} {1}", dwt.Width, dwt.Height)); 
     } 

     public Window1() 
     { 
      InitializeComponent(); 
      Points = new ObservableCollection<RectanglePoints>(); 
      Random rand = new Random(); 
      for(int i=0; i<10; i++) { 
       Points.Add(new RectanglePoints { UL=new Point { X=rand.Next(), Y=rand.Next() }, 
                UR=new Point { X=rand.Next(), Y=rand.Next() }, 
                LL=new Point { X=rand.Next(), Y=rand.Next() }, 
                LR=new Point { X=rand.Next(), Y=rand.Next() } 
               }); 
      } 

      Sample(); 
     } 
    } 
} 

REMARQUE: ne pas essayer de courir sauf si vous ajoutez en fait les clés du Dictionnaire :)

La création de la classe anonyme dans LINQ est géniale, mais elle me force à faire le calcul en une ligne. Imagine que le calcul est beaucoup plus long que ce que j'ai montré. Mais il est similaire en ce que je vais faire quelques recherches de dictionnaire pour obtenir des valeurs spécifiques. Le débogage pourrait être douloureux.

L'utilisation d'une classe concrète contourne ce problème d'utilisation de variables temporaires, mais je ne peux pas tout faire de façon concise. Oui, je me rends compte que je suis un peu contradictoire en disant que je cherche la concision, tout en demandant de pouvoir enregistrer des variables temporaires dans mon instruction LINQ.

Je commençais à essayer de créer une classe anonyme en bouclant des points, mais j'ai vite réalisé que je n'avais aucun moyen de la stocker! Vous ne pouvez pas utiliser une liste, car cela perd tout l'anonymat de la classe.

Quelqu'un peut-il suggérer un moyen de réaliser ce que je cherche? Ou un terrain d'entente? J'ai lu quelques autres questions ici sur StackOverflow, mais aucune d'elles n'est exactement la même que la mienne.

Répondre

5

En supposant que je vous comprenne correctement, le problème est que vous devez définir toutes les propriétés dans une seule expression. C'est certainement le cas avec les types anonymes.

Cependant, vous n'avez pas besoin de tout faire en ligne dans cette expression. Je suggère que si vos propriétés sont basées sur des expressions complexes, vous cassez ces expressions sur les méthodes d'aide:

var complex = new { 
     First = ComputeFirstValue(x, y), 
     Second = ComputeSecondValue(a, b) 
     ... 
}; 

Ceci a l'avantage potentiel supplémentaire que vous pouvez tester l'unité de chacune des méthodes d'assistance individuelle, si vous re un fan de tests en boîte blanche (je suis).

Cela n'empêchera pas l'existence d'une grande expression d'initialisation de type anonyme, mais cela signifie que le travail sera interrompu.

+0

vous m'avez bien compris. Merci de m'avoir confirmé cela, et votre idée est géniale! – Dave

1

Les classes anonymes sont vraiment destinées à simplifier les choses traitant de lambdas, pas moins LINQ. Ce que vous essayez de faire semble beaucoup plus adapté à une classe privée imbriquée. De cette façon, seule votre classe connaît vraiment votre classe de temp.Essayer de balayer avec des classes anonymes ne fait que compliquer votre code.

Questions connexes