2011-03-07 14 views
5

Tengo el siguiente bloque de consultas de linq para calcular algunos valores para un informe.¿Por qué los valores de mis consultas linq no aparecen inmediatamente?

var items = (from trans in calclabordb.Sales_Transactions     
      select trans).SelectMany(st => st.Sales_TransactionLineItems).Where(stli => stli.TypeID == typeID); 

decimal test = items.Where(stli => stli.Inventory_Item is Base).Sum(stli => (decimal?)stli.Inventory_Item.IntExtraServiceAmount) ?? 0; 
decimal test2 = items.Where(stli => stli.Inventory_Item is Extra).Sum(stli => (decimal?)stli.ItemPrice) ?? 0; 
decimal test3 = test + test2; 
current.ExtraSales = items.Where(stli => stli.Inventory_Item is Base).Sum(stli => (decimal?)stli.Inventory_Item.IntExtraServiceAmount) ?? 0 + 
    items.Where(stli => stli.Inventory_Item is Extra).Sum(stli => (decimal?)stli.ItemPrice) ?? 0; 

He pasado por el código en un depurador y he notado algunas rarezas. Después de asignar en test su valor es 0. Después de asignar en test2test2 == 0 y test == 11.31 después de asignar en test3 test == 11.31test2 == 11.28 y test3 == 22.59 después de asignar en ExtraSalesExtraSales == 11.31. El valor en ExtraSales cuando todo este completo debe ser 22.59. ¿Que está pasando aqui?

EDITAR: He agregado líneas adicionales después de la asignación en ExtraSales pero el valor no cambia.

Respuesta

22

Las respuestas que decir que este es un problema de ejecución diferida están equivocados. Es un problema de precedencia del operador.

Deshágase de todo ese código completamente irrelevante e imposible de leer que existe. Todo es arenque rojo. La repro relevante es:

decimal? d1 = 11.31m; 
decimal? d2 = 11.28m; 
decimal test1 = d1 ?? 0m; 
decimal test2 = d2 ?? 0m; 
decimal test3 = test1 + test2; 
decimal test4 = d1 ?? 0m + d2 ?? 0m; 

¿Cuál es el significado de la última línea? ¿Significa lo mismo que la línea anterior?

No, no es así. El operador de suma es mayor precedencia que el operador coalescente nula, por lo que este es

decimal test4 = d1 ?? (0m + d2) ?? 0m; 

el código que escribió significa "producir el valor de D1 si D1 no es nulo. Si d1 es nula y 0m + d2 es no nulo, entonces produce el valor de 0m + d2. Si 0m + d2 es nulo, entonces produce el valor 0m ".

(no podría haber sabido que el operador ?? tiene esta propiedad encadenamiento agradable. En general, a ?? b ?? c ?? d ?? e le da el primer valor no nulo de a, b, c, d, ye si son por lo demás todo nula Puede hacer la cadena todo el tiempo que desee. Es un pequeño operador bastante elegante.

Como d1 no es nulo, producimos su valor y test4 tiene asignado el valor de d1.

Probablemente quería decir:

decimal test4 = (d1 ?? 0m) + (d2 ?? 0m); 

Si se refiere a "D1 o D2 podría ser nulo, y si bien es, a continuación, tratar el nulo como cero".Así que 12 + 2 es 14, 12 + nula es 12, null + nula es 0

Si usted quiere decir "ya sea D1 y D2 podría ser nulo, y si ya sea es nulo luego quiero cero", eso es

decimal test4 = (d1 + d2) ?? 0m; 

así que 12 + 2 es 14, 12 + nula es 0, null + nula es 0

observo que si se hubiera formateado el código para que el texto en cuestión estaba en la pantalla, es probable que wouldn' Han recibido cinco o más respuestas incorrectas publicadas primero. Intente formatear su código para que todo esté en la pantalla; obtendrás mejores respuestas si lo haces.

+0

Respondido como un profesional. –

+0

Sabes que debería haberlo sabido mejor. Me he encontrado con ese problema de precedencia en el pasado en un escenario donde? tenía mayor prioridad que otro operador. El depurador parece haberme dado información engañosa. – Mykroft

-1

Sí, se llama ejecución diferida y es una de las cosas que pueden ser muy potente, pero también le dispare para arriba si usted no está esperando que ...

Cuestiones relacionadas