Autor Beitrag
Glowhollow
ontopic starontopic starontopic starontopic starontopic starontopic starontopic starhalf ontopic star
Beiträge: 77



BeitragVerfasst: Fr 25.01.19 18:30 
Hallo,

ich bin im Netz über folgenden Code gestolpert, den ich auch gleich mitkommentiere, damit ihr sehen könnt, was ich verstanden habe, und was nicht.

ausblenden volle Höhe C#-Quelltext
1:
2:
3:
4:
5:
6:
7:
8:
9:
10:
11:
12:
13:
14:
15:
16:
17:
18:
19:
20:
21:
22:
23:
24:
25:
26:
27:
28:
29:
30:
31:
32:
33:
34:
35:
36:
37:
38:
39:
40:
41:
42:
43:
44:
45:
46:
class Primes {  //klassenerstellung, gibts nicht viel zu ssagen
    static IEnumerable<int> DividerSequence() { //hier wird die Funktion DividerSequence erstellt, welches das IEnumerable Interface vom Typ Integer zurückgibt, bzw. definiert
        yield return 2// ja und hier setzt es bei mir aus. Was bewirkt yield, wo kommt es her und und warum hab ich hier mehrere return werte ? Ich dachte nach dem return, wäre die 
                        // Funktion/methode beendet ?
        yield return 3;
        for(int i = 6true; i+=6){ // keine Ahnung warum er das hier macht.
            yield return i - 1;
            yield return i + 1;
        }
    }

    public static ICollection<int> GetPrimeFactors(int number) { // das hier ist klar, gebe ne ICollection aus Integern (die primfaktoren) zurück, die Methode nimmt integer an
        if (number <= 0) {                                                        // simple prüfung ob, der wert kein negativer wert ist.
            throw new ArgumentException("Positive integer expected.""number");  // throw execption, wenn negativ
        }

        LinkedList<int> primeFactors = new LinkedList<int>(); // Hier wird ne linked list erstellt, welche die Primfaktoren aufnimmt
        foreach (int factor in DividerSequence()) { // foreach Schleife zum durchiterieren der daten aus DividerSequence
            while (number % factor == 0) { //while anweisung, soweit klar mit modulo
                primeFactors.AddLast(factor); // häng an die Linked List, die entsprechende Primzahl an
                number /= factor;
            }
            if (factor * factor > number) { // wenn die primzahl * primzahl größer ist als die Zahl ist, die faktorierst werden soll, abbruch
                break;
            }
        }
        if (number > 1) { // wenn der rest nicht weiter faktorisierbar ist, und die zahl größer ist als 1
            primeFactors.AddLast(number); // hänge den letzten nicht faktorisierbaren wert an die Linked List
        }
        return primeFactors; // rückgabe
    }
}

// der rest hier ist klar, kommentier ich erst mal nicht weiter.

class Program{
    static void Main(string[] args) {
        for (int number = 1; number < 100; number++) {
            ICollection<int> primeFactors = Primes.GetPrimeFactors(number);
            Console.WriteLine(
                "n={0}, Primes=[{1}]",
                number,
                string.Join(", ", primeFactors.Select(x => x.ToString()).ToArray()));
        }
    }
}


speziell verstehe ich Yield nicht so ganz, auch die Dokumentation von Microsoft, ist so mit fachwörten gespickt, das ich mir schwer tue es zu verstehen.

Ich kann natürlich das ganze jetzt im debugger laufen lassen und gucken, was er da genau macht, aber ich möchte ja verstehen, was hier passiert.

Kann mich hier jemand n bischen erleuchten ?
Th69
ontopic starontopic starontopic starontopic starontopic starontopic starontopic starontopic star
Moderator
Beiträge: 4764
Erhaltene Danke: 1052

Win10
C#, C++ (VS 2017/19/22)
BeitragVerfasst: Fr 25.01.19 19:07 
Ein Methode, mit dem Schlüsselwort yield return innerhalb, wird vom Compiler intern in eine State-Machine übersetzt, so daß bei jedem Aufruf der Methode der nachfolgende Code (nach dem yield return) weiter ausgeführt wird. Wichtig dabei ist, daß der Rückgabetyp IEnumerable<T> ist, so daß eine Folge generiert wird.
Bei statischen Werten würde man z.B. eine List<T> zurückgeben:
ausblenden C#-Quelltext
1:
2:
3:
4:
List<int> Test()
{
  return new List<int> { 235711131719 };
}

Bei der Methode DividerSequence() wird quasi eine unendliche Liste erzeugt, aber eben mittels "Lazy Evaluation" ausgewertet, d.h. erst wenn wirklich auf die generierte Enumeration zugegriffen wird.

Der Code
ausblenden C#-Quelltext
1:
2:
foreach (int x in DividerSequence())
   Console.WriteLine(x);
erzeugt also diese unendliche Liste von Primfaktorkandidaten.

Edit: Durch yield break oder wenn das Ende der Methode erreicht ist, wird kein weiteres Element der Folge mehr generiert - was meistens benutzt wird, um endliche Folgen (Auflistungen) zu generieren.

Etwas ausführlicher wird es noch unter Essential .NET: Benutzerdefinierte Iteratoren mit „yield“ sowie Yield return in C# (auf englisch) erklärt.

PS: Die Schleife mit +=6 wird genommen, da dies eine Optimierung gegenüber +=2 (nur ungerade Zahlen ist), da ja alle durch 3 teilbaren ungeraden Zahlen (9, 15, 21, ...) keine Primzahlen sein können.