Was komisches mit Linq und Tuple

  • VB.NET

Es gibt 4 Antworten in diesem Thema. Der letzte Beitrag () ist von Niko Ortner.

    Was komisches mit Linq und Tuple

    Folgender Test-Code:

    VB.NET-Quellcode

    1. Dim itms = {Tuple.Create(9), Tuple.Create(10)}.ToList
    2. Dim query1 = itms.Where(Function(x) x.Item1 = 9)
    3. Dim query2 = From x In itms Where x.Item1 = 9
    Zeile #3 geht nicht: "Option Strict On disallows late binding." - also er erkennt nicht, dass x ein Tuple(Of Integer) ist
    Nach meim Verständnis sind Zeilen#2+3 aber nur verschiedene Formulierungen, die exakt denselben IL-Code ergeben sollten.
    Ist das womöglich ein vs2019-Bug?

    Dieses hier zB geht:

    VB.NET-Quellcode

    1. Dim itms = {New With {.Item1 = 9}, New With {.Item1 = 10}}.ToList
    2. Dim query1 = itms.Where(Function(x) x.Item1 = 9).ToList
    3. Dim query2 = From x In itms Where x.Item1 = 9
    (Statt Tuple(Of Integer) mit anonymen Typ)
    Bilder
    • Bild000097.png

      8,46 kB, 803×74, 75 mal angesehen

    Dieser Beitrag wurde bereits 1 mal editiert, zuletzt von „ErfinderDesRades“ ()

    Läuft bei mir. Sowohl zur Design- als auch Laufzeit.
    VS 2019 CE 16.8.1
    Bilder
    • Tuples.png

      10,96 kB, 655×206, 78 mal angesehen
    • IntelliSense 1.png

      8,81 kB, 634×119, 64 mal angesehen
    • IntelliSense 2.png

      10,15 kB, 611×121, 68 mal angesehen
    • IntelliSense 3.png

      10,17 kB, 598×108, 74 mal angesehen
    Dieser Beitrag wurde bereits 5 mal editiert, zuletzt von „VaporiZed“, mal wieder aus Grammatikgründen.

    Aufgrund spontaner Selbsteintrübung sind all meine Glaskugeln beim Hersteller. Lasst mich daher bitte nicht den Spekulatiusbackmodus wechseln.
    Nee - das wars nicht. Es war eine Extension, die irgendwie recht verschwurbelt einen Namenskonflikt verursachte - verstanden habich da noch nicht.



    Aber nächste Wunderlichkeit:

    VB.NET-Quellcode

    1. Public Class Item
    2. Public Data As Integer?
    3. End Class
    4. Private Sub Wunderlichkeit()
    5. Dim itms = {New Item With {.Data = 9}, New Item With {.Data = 10}, New Item}.ToList
    6. Dim query0 = itms.Where(Function(x) x.Data = 9) ' diesen Fehler verstehe ich, weil 'x.Data = 9' ergibt Nullable(Of Boolean)
    7. Dim query1 = itms.Where(Function(x) x.Data.GetValueOrDefault = 9) ' deshalb muss man mit .GetValueOrDefault behelfen
    8. Dim query2 = From x In itms Where x.Data = 9 ' oder man formuliert so - dann gehts auch ohne ????
    9. End Sub
    Das Spannende hier ist Zeile#8 - warum kompiliert das, während zeile#6 nicht geht?

    Dieser Beitrag wurde bereits 1 mal editiert, zuletzt von „ErfinderDesRades“ ()

    Ich vermute ins Blaue, dass der Compiler bei query2 weiß, dass der Where-Ausdruck einen Boolean ergeben muss und deshalb die Extension mit dem Nullable(Of Boolean) garnicht erst in Betracht zieht.
    Mal probieren...

    VB.NET-Quellcode

    1. Imports System.Runtime.CompilerServices
    2. Public Class Item
    3. Public Data As Integer?
    4. End Class
    5. Public Class Program
    6. Public Shared Sub Main(Args As String())
    7. Dim itms = {New Item With {.Data = 9}, New Item With {.Data = 10}, New Item}.ToList
    8. Dim query0 = itms.Where(Function(x) x.Data = 9) ' Schmeißt "Where mit Nullable(Of Boolean)"
    9. Dim query1 = itms.Where(Function(x) x.Data.GetValueOrDefault = 9) ' Schmeißt "Where mit Boolean"
    10. Dim query2 = From x In itms Where x.Data = 9 ' Schmeißt "Where mit Boolean"
    11. End Sub
    12. End Class
    13. Public Module Extensions
    14. <Extension()>
    15. <DebuggerStepThrough()>
    16. Public Function Where(Of T)(Items As IEnumerable(Of T), Predicate As Func(Of T, Boolean)) As IEnumerable(Of T)
    17. Throw New Exception("Where mit Boolean")
    18. End Function
    19. <Extension()>
    20. <DebuggerStepThrough()>
    21. Public Function Where(Of T)(Items As IEnumerable(Of T), Predicate As Func(Of T, Boolean?)) As IEnumerable(Of T)
    22. Throw New Exception("Where mit Nullable(Of Boolean)")
    23. End Function
    24. End Module

    Lag wohl richtig.

    Dekompiliert man das, sieht man, dass bei query2 GetValueOrDefault vom Compiler eingefügt wird:

    CIL-Quellcode

    1. // ConsoleApplication1.Program
    2. [STAThread]
    3. public static void Main(string[] Args)
    4. {
    5. List<Item> itms = new Item[]
    6. {
    7. new Item
    8. {
    9. Data = 9
    10. },
    11. new Item
    12. {
    13. Data = 10
    14. },
    15. new Item()
    16. }.ToList<Item>();
    17. IEnumerable<Item> query0 = itms.Where(new Func<Item, bool?>(Program._Lambda$__1));
    18. IEnumerable<Item> query = itms.Where(new Func<Item, bool>(Program._Lambda$__2));
    19. IEnumerable<Item> query2 = itms.Where(new Func<Item, bool>(Program._Lambda$__3));
    20. }
    21. // ConsoleApplication1.Program
    22. [CompilerGenerated]
    23. private static bool? _Lambda$__1(Item x)
    24. {
    25. int num = 9;
    26. int? data = x.Data;
    27. if (!data.HasValue)
    28. {
    29. return null;
    30. }
    31. bool? result = new bool?(data.GetValueOrDefault() == num);
    32. return result;
    33. }
    34. // ConsoleApplication1.Program
    35. [CompilerGenerated]
    36. private static bool _Lambda$__2(Item x)
    37. {
    38. return x.Data.GetValueOrDefault() == 9;
    39. }
    40. // ConsoleApplication1.Program
    41. [CompilerGenerated]
    42. private static bool _Lambda$__3(Item x)
    43. {
    44. int num = 9;
    45. int? data = x.Data;
    46. bool? arg_32_0;
    47. if (!data.HasValue)
    48. {
    49. arg_32_0 = null;
    50. }
    51. else
    52. {
    53. bool? flag = new bool?(data.GetValueOrDefault() == num);
    54. arg_32_0 = flag;
    55. }
    56. bool? flag2 = arg_32_0;
    57. return flag2.GetValueOrDefault();
    58. }
    "Luckily luh... luckily it wasn't poi-"
    -- Brady in Wonderland, 23. Februar 2015, 1:56
    Desktop Pinner | ApplicationSettings | OnUtils