Domanda

Sono nuovo di classi anonime, e oggi penso che mi sono imbattuto nel primo caso in cui mi sono sentito come se potessi davvero usarli. Sto scrivendo un metodo che trarrebbero beneficio da memorizzare all'interno di dati temporanea di una classe, e dal momento che la classe non ha alcun senso al di fuori di tale metodo, utilizzando una classe anonima certo senso per me (almeno al momento lo ha fatto ).

Dopo aver avviato sulla codifica, è certo che sembrava come se fossi costretta a fare alcune concessioni. Mi piace mettere cose assegnare come calcoli alle variabili temporanee, in modo che durante il debugging posso verificare bit di calcoli in un momento in blocchi logici. Poi voglio assegnare qualcosa di più semplice al valore finale. Questo valore sarebbe nella classe anonima.

Il problema è che, al fine di implementare il mio codice con le classi anonime conciso, mi piacerebbe usare LINQ. Il problema qui è che non credo che si può fare questi calcoli temporanei all'interno della dichiarazione. oppure è possibile?

Ecco un esempio forzato di quello che voglio fare:

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();
        }
    }
}

Nota: non tentare di eseguire questo a meno che in realtà aggiungere le chiavi al dizionario :)

La creazione della classe anonima in LINQ è impressionante, ma mi costringe a fare il calcolo in una riga. Immaginate che il calc è il modo più lungo di quello che ho mostrato. Ma è simile in che farò alcune ricerche dizionario per ottenere valori specifici. Debug potrebbe essere doloroso.

L'utilizzo di una classe concreta aggira questo problema dell'utilizzo di variabili temporanee, ma poi non può fare tutto in modo conciso. Sì, mi rendo conto che devo essere un po 'contraddittorio nel dire che sto cercando concisione, chiedendo di essere in grado di salvare le variabili temporanee nella mia dichiarazione LINQ.

I stava iniziando a cercare di creare una classe anonima quando ciclare su punti, ma ben presto si rese conto che non ho avuto modo di conservarlo! Non è possibile utilizzare un elenco perché solo perde l'intero anonimato della classe.

Qualcuno può suggerire un modo per ottenere ciò che sto cercando? O qualche via di mezzo? Ho letto alcune altre domande qui su StackOverflow, ma nessuno di loro sono esattamente uguale al mio.

È stato utile?

Soluzione

Supponendo ho capito bene, il problema è che è necessario impostare tutte le proprietà di una singola espressione. Questo è sicuramente il caso di tipi anonimi.

Tuttavia, non c'è bisogno di fare tutto in linea in quell'espressione. Vorrei suggerire che se le proprietà sono basate sulle espressioni complesse, si interrompe quelle espressioni fuori in metodi di supporto:

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

Questo ha il potenziale ulteriore vantaggio che si può unit test ciascuno dei metodi di supporto singolarmente, se sei un fan di test white-box (io sono).

Questo non sta andando per evitare che vi sia in un unico grande tipo anonimo initializer espressione, ma significa che il lavoro sarà suddiviso.

Altri suggerimenti

Le classi anonime siano veramente destinati a semplificare trattare cose con lambda, non da ultimo LINQ. Quello che stai cercando di fare suoni molto più adatto a una classe privata nidificato. In questo modo, solo la classe conosce veramente la classe di temperatura. Cercando di impazzire con le classi anonime sembra solo a complicare il codice.

Autorizzato sotto: CC-BY-SA insieme a attribuzione
Non affiliato a StackOverflow
scroll top