IEnumerable Basiswissen Schnittstelle

  • VB.NET
  • .NET (FX) 4.5–4.8

Es gibt 9 Antworten in diesem Thema. Der letzte Beitrag () ist von ErfinderDesRades.

    IEnumerable Basiswissen Schnittstelle

    Hallo,

    Einige Sachen geben eine Auflistung als IEnumerable(Of T) zurück. Das ist ja eigentlich eine Schnittstelle, warum kann man die genauso nutzen wie eine Klasse?
    Ist eine Schnittstelle generell eine Klasse? Normalerweise sagt der Code in einer Schnittstellendefinition ja nicht was Sache ist.

    Viele Grüße
    Ja, IEnumerable ist eine Schnittstelle. Aber hier geht es darum, dass Du etwas zurückbekommst, welches diese Schnittstelle implementiert. Beispiel Auto, Fahrrad, Panzer, welche die Schnittstelle FahrbahresEtwas mit der Methode Fahren implementieren. Wenn Du von einem Kumpel eine Sache haben willst, die fahren kann, deren Methode Fahren Du also ausführen kannst, ist es Dir wurscht, ob Du ein Auto, einen Panzer oder ein Fahrrad von Deinem Kumpel bekommst, Hauptsache Du kannst damit fahren.

    VB.NET-Quellcode

    1. Dim IrgendwasWasFahrenKann = GibMirWasZumFahren()
    2. IrgendwasWasFahrenKann.Fahren()
    3. Private Function GibMirWasZumFahren() As FahrbahresEtwas
    4. If HeuteIstWochentag Then Return MeinAuto
    5. If HeuteHabIchMeinenPanzerSchönGemacht Then Return MeinLeopard2
    6. If HeuteIstWochenendeUndDerSpritIstTeuer Then Return MeinRotesMountainbike
    7. End Function

    Wenn Du also schreibst, dass eine Funktion ein IEnumerable(Of WasAuchImmer) zurückgeben soll, ist es egal, was da zurückgegeben wird, Hauptsache, es implementiert IEnumerable(Of WasAuchImmer), »kann« also alles der Schnittstelle IEnumerable(Of WasAuchImmer), kann also aufgezählt werden bzw. mit einem Enumerator durchgegangen werden, in ein Array oder eine List gewandelt werden, …
    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.

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

    Ok, dann habe ich das ja zumindest noch auf dem Schirm gehabt.

    Ich habe hieran gebastelt:

    VB.NET-Quellcode

    1. Private Function GetFileList(targetdirectory As String) As IEnumerable(Of SftpFile)
    2. Dim FileList As IEnumerable(Of SftpFile)
    3. Try
    4. Using sftp As New SftpClient(xHost, 22, xUsername, xPassword)
    5. sftp.Connect()
    6. FileList = sftp.ListDirectory(targetdirectory)
    7. sftp.Disconnect()
    8. End Using
    9. Return FileList
    10. Catch e As Exception
    11. CWrite(Err.Description)
    12. Return Array.Empty(Of SftpFile) 'Hier war ich erst nich sicher wie ich es umsetze. Aber da ein Array ja IEnumerable implementiert, macht das so sicher Sinn
    13. End Try
    14. End Function
    15. Private Sub ListFiles(files As IEnumerable(Of SftpFile)) 'Auch in Verbindung hiermit bin ich nicht sicher, ich speicher ja quasi das Ergebnis der Funktion und rufe es dann eventuell hier wieder als Argument ab. Sollte das stattdessen erst in eine "echte" Instanz gepflegt werden? z.B. List(Of T)
    16. For Each file In files
    17. Dim size As String
    18. If file.IsDirectory = False Then
    19. Select Case file.Length
    20. Case > 999999
    21. size = $"{Math.Round(file.Length / 1000000, 2)} MB".PadLeft(9, "_"c)
    22. Case Else
    23. size = $"{Math.Round(file.Length / 1000, 2)} kB".PadLeft(9, "_"c)
    24. End Select
    25. CWrite($"{file.Name}{vbTab}{size}{vbTab}{file.LastWriteTime}")
    26. End If
    27. Next
    28. End Sub
    29. 'Aufruf:
    30. Dim x = GetFileList("...") 'Oder hier .ToList .ToArray?
    31. If x.Count >0 Then ListFiles(x)


    Weil so gesehen übergebe ich "Fahren" und das ist ja gar keine Sache, also besser erst festlegen was da kommt Auto oder Fahrrad?

    Dieser Beitrag wurde bereits 2 mal editiert, zuletzt von „Haudruferzappeltnoch“ ()

    Der Methode ListFiles - wie du sie jetzt gemacht hast - kannst du verschiedenes übergeben: List(Of SftpFile), SftpFile-Array, HashSet(Of SftpFile), weitere typisierte auflistungen.
    Das ist architektonisch günstig, wenn du die Methode von verschiedenen Stellen aufrufen willst, mit evtl. verschiedenen Auflistungs-Typen.
    Oder wenn du mal drauf kommst, dass ein anderer Auflistungstyp doch günstiger isst.

    Warum sollte es nun besser sein, erst Auto oder Fahrrad festzulegen (was immer du mit diesem Gleichnis nun genau meinst)?
    Ich denke es ist schon fast alles gesagt worden.

    Ich merke mir das immer so.

    Der IEnumerator(of T) ist wie schon oben beschrieben eine Schnittstelle. Viel wichtiger aber ist zu wissen, dass diese Schnittstelle einen Enumerator (DatenStruktur mit MoveNext-Funktion und endlichem Wertebereich) verfügbar macht. Und somit können Enumeratoren mit einer Iteration durchlaufen werden.

    Da es sich hier um eine IEnumerator(of T) handelt ist der Enumerator generisch, d.h. dass dieser Enumerator für den spezifisch dazu deklarierten DatenTyp T (oder auch eigen erstellte Klassendatentyen) verwendet werden kann.

    Die IEnumeartor(of T) wird von vielen .Net-Werkzeugen zurückgegeben, wie z.b. List(of T), Array(of T) etc. Einfach gesagt sind es alle Werkzeuge die die GetEnumerator-Methode besitzen.

    Was für die IEnumerable gebraucht wird, besteht nun. Es spielt keine Rolle ob auf Array(of T) gewechselt wird, oder von Array(of T) zu einer List(of T), oder wiederum zu einer eigenen Collection(of T) (siehe Beispiel unten). Da IEnumerable(of T) eine Schnittstelle ist, verbindet sie all diese Werkzeuge miteinander.

    Spoiler anzeigen

    C#-Quellcode

    1. using System.Collections;
    2. namespace Test;
    3. public class Program
    4. {
    5. private static readonly Random Rand = new();
    6. public static void Main()
    7. {
    8. Test1();
    9. Test2();
    10. Test3();
    11. Console.ReadLine();
    12. }
    13. public static void Test1()
    14. {
    15. IEnumerable<int> myarray = new[] { 0, 1, 2, 3, 4, 5, 6, 7, 8, 9 };
    16. using var emyarray = myarray.GetEnumerator();
    17. while (emyarray.MoveNext()) Console.Write(emyarray.Current);
    18. Console.WriteLine();
    19. IEnumerable<int> mylist = new List<int> { 0, 1, 2, 3, 4, 5, 6, 7, 8, 9 };
    20. using var emylist = mylist.GetEnumerator();
    21. while (emylist.MoveNext()) Console.Write(emylist.Current);
    22. Console.WriteLine();
    23. Console.WriteLine();
    24. }
    25. public static void Test2()
    26. {
    27. var myobjects = RngMyObject(5);
    28. for (var i = 0; i < myobjects.Length; i++)
    29. Console.WriteLine(myobjects[i].ToString());
    30. Console.WriteLine();
    31. }
    32. public static void Test3()
    33. {
    34. var myobjects = RngMyObject(5);
    35. var myobj = new MyObjectCollection(myobjects);
    36. var itm = 0;
    37. Console.WriteLine(myobj.ToString());
    38. //Directly to GetEnumerator
    39. var eomyobj = myobj.GetEnumerator();
    40. while (eomyobj.MoveNext()) Console.WriteLine($"{itm++}: {eomyobj.Current}");
    41. Console.WriteLine();
    42. //Over IEnumerable<T>
    43. var eamyobj = myobj.AsEnumerable();
    44. using var emyobj2 = eamyobj.GetEnumerator();
    45. while (emyobj2.MoveNext()) Console.WriteLine($"{itm++}: {emyobj2.Current}");
    46. Console.WriteLine();
    47. Console.WriteLine();
    48. }
    49. private static MyObject[] RngMyObject(int size)
    50. {
    51. return Enumerable.Range(0, size).Select(x => new MyObject { Id = Rand.Next(), Name = $"Name_{x}" }).ToArray();
    52. }
    53. }
    54. public class MyObjectCollection : IEnumerable<MyObject>, IEnumerable
    55. {
    56. private readonly List<MyObject> InternalList = new();
    57. public MyObject this[int index]
    58. {
    59. get { return this.InternalList[index]; }
    60. set { this.InternalList.Insert(index, value); }
    61. }
    62. public MyObjectCollection() { }
    63. public MyObjectCollection(IEnumerable<MyObject> soruce)
    64. {
    65. this.InternalList.AddRange(soruce);
    66. }
    67. public IEnumerator GetEnumerator()
    68. => this.InternalList.GetEnumerator();
    69. IEnumerator<MyObject> IEnumerable<MyObject>.GetEnumerator()
    70. {
    71. foreach (var itm in this.InternalList)
    72. yield return itm;
    73. //Das würde auch gehen.
    74. //return this.InternalList.GetEnumerator();
    75. }
    76. public override string ToString()
    77. {
    78. return $"{nameof(MyObjectCollection)}: count: {this.InternalList.Count}";
    79. }
    80. }
    81. public class MyObject
    82. {
    83. public int Id = 0;
    84. public string Name = string.Empty;
    85. public MyObject() { }
    86. public MyObject(int id, string name)
    87. {
    88. this.Id = id;
    89. this.Name = name;
    90. }
    91. public override string ToString()
    92. {
    93. return $"{this.Id}: \t{this.Name}";
    94. }
    95. }



    Freundliche Grüsse

    exc-jdbi

    Dieser Beitrag wurde bereits 4 mal editiert, zuletzt von „exc-jdbi“ ()

    Ich würd das als Nichtinformatiker so formulieren. Von dem Objekt, das zurückgegeben wird, wird alles entfernt, was nicht IEnumerable(Of T) ist. Es bleibt also nur der Teil des Objekts übrig, »der durch den IEnumerable(Of T)-Filter durchgelangt«. Alles andere bleibt auf der Strecke.
    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.

    Haudruferzappeltnoch schrieb:

    Verstehe, ich denke die ListDirectory Methode ist der Punkt hier. Also wenn die ein IEnumerable zurückgibt, dann ist das aber auch ein echte Instanz von irgendwas, oder? Obwohl es keine Klasse gibt
    keine Ahnung - kann man im Code sso nicht erkennen, was die zurückgibt.
    Der gezeigte Code wäre auch richtig, wenn ListDirectory() eine List(Of SftpFile) returntete.
    guck das nochmal nach, was die Methode returnt.
    Was sie zurückgibt, geht übrigens über IEnumerable hinaus: sie gibt ein IEnumerable(Of SftpFile) zurück - dassis was anneres.