2013-05-09 3 views
9

Ecco alcuni codice che (ovviamente) non compila:Sintassi per eseguire il blocco di codice all'interno della query di Linq?

var q = from x in myAnonymousTypeCollection 
     select new { 
      x.ID, 
      CalcField = { 
         switch(x.SomeField) { 
          case 1: 
          return Math.Sqrt(x.Field1); 
          case 2: 
          return Math.Pow(x.Field2, 2); 
          default: 
          return x.Field3; 
         } 
         } 
     }; 

Si ottiene l'immagine; Sto cercando di calcolare CalcField in un modo completamente diverso, a seconda di quale sia il valore di SomeField. Non riesco a utilizzare uno Func<> (o posso?), Perché il tipo di input è anonimo. Quindi qual è la sintassi giusta per farlo funzionare?

+0

È questo Linq to Objects? – cadrell0

+1

Utilizzare una lambda o una funzione anonima. –

+0

@ofstream - So che potrei farlo usando un lambda, ma per ragioni di leggibilità nel mio codice attuale, voglio usare la sintassi della query. –

risposta

9

Prima di tutto, di solito preferisco la sintassi della catena del metodo sulla sintassi della query per Linq. Con quello puoi farlo facilmente.

var q = myAnonymousTypeCollection 
    .Select(x => 
      { 
       object calcField; 

       switch(x.SomeField) 
       { 
         case 1: 
         calcField = Math.Sqrt(x.Field1); 
         case 2: 
         calcField = Math.Pow(x.Field2, 2); 
         default: 
         calcField = x.Field3; 

       return new 
         { 
          x.ID, 
          CalcField = calcField 
         }; 
      }); 

Senza utilizzare le catene di metodi, è necessario un metodo o un Func. Supponiamo un Func

//replace these with actual types if you can. 
Func<dynamic, dynamic> calculateField = 
    x => 
    { 
     switch(x.SomeField) { 
      case 1: 
       return Math.Sqrt(x.Field1); 
      case 2: 
       return Math.Pow(x.Field2, 2); 
      default: 
       return x.Field3; 
    } 

var q = from x in myAnonymousTypeCollection 
     select new { x.Id, CalcField = calculateField(x) }; 

Nota: non l'ho scritto in un IDE, quindi scusate qualsiasi semplice errore.

Questo è il MSDN per dynamic. Tuttavia, ho scoperto che una volta che hai bisogno di iniziare a passare i tipi anonimi, è meglio creare una classe reale.

+0

+1 Ooh, subdolo, usando 'dynamic'! Preferisco i tipi forti, e finora ho scelto la prima opzione (sintassi lambda). In attesa di una sintassi di query valida (se ne esiste una) prima di fornire un credito di risposta. :-) –

7

È possibile eseguire il wrapping della funzione anonima come delegato (con esecuzione automatica) Func<>. Questo presuppone che tu conosca il tipo di reso.

var q = from x in myAnonymousTypeCollection 
    select new { 
     ID = x.ID, 
     CalcField = new Func<double>(() => { 
        switch(x.SomeField) { 
         case 1: 
         return Math.Sqrt(x.Field1); 
         case 2: 
         return Math.Pow(x.Field2, 2); 
         default: 
         return x.Field3; 
        } 
        })() 
    }; 
+0

+1: è bello! il concetto è simile a javascript: esegui la funzione anonima: '(function() {...})();' –

+0

Nota che in una situazione come questa è probabilmente meglio da un punto di vista di leggibilità/manutenzione estrarre questo verso una funzione con nome che chiami semplicemente nella query LINQ, anche se funzionerà. – Servy

+0

+1 molto bello. Cosa succede se il tipo di reso è anche anonimo? :-) –

0

Si potrebbe facilmente spostare la logica interruttore fuori in un'altra funzione in questo modo:

private static T GetReturnValue<T>(myClass x) 
{ 
    switch (x) 
    { 
     case 1: 
      return Math.Sqrt(x.Field1); 
      break; 
     case 2: 
      return Math.Pow(x.Field2, 
          2); 
      break; 
     default: 
      return x.Field3; 
      break; 
    } 
} 

e poi basta solo bisogno di passare l'oggetto a quella funzione per recuperare il valore che si desidera:

var q = from x in myAnonymousTypeCollection 
        select new 
         { 
          ID = x.ID, 
          CalcField = GetReturnValue(x) 
         }; 
+0

Certo, sarebbe facile se avessi un tipo definito, come fai tu ('myClass'). Ma sto usando un tipo anonimo ... –

Problemi correlati