lokale funktionen c#

  • C#
  • .NET 7–8

Es gibt 11 Antworten in diesem Thema. Der letzte Beitrag () ist von siycah.

    lokale funktionen c#

    Hallo,

    c# kann ich eigentlich einigermaßen lesen und schreiben. Aber wirklich gecodet hab ich in c# noch nicht.
    Bin bei meinen ersten Experimenten direkt auf sowas gestoßen
    wildes Beispiel

    C#-Quellcode

    1. static int Foo(int a, int b)
    2. {
    3. return Bar(a,b);
    4. int Bar(int c, int d)
    5. { return c + d; }
    6. }
    Das gibts in vb nicht, eine Funktion in einer Funktion. Nennt sich wohl lokale Funktion. Anscheinend relativ neu, erinnert mich bissle an python.
    Was da in der Doku zu den Anwendungsbeispielen steht wirkt auf mich schon eher etwas advanceder.

    Gibts da auch irgendwelche grundlegenden Überlegungen, die man sich zu dieser Neuerung machen sollte?

    Viele Grüße

    Haudruferzappeltnoch schrieb:

    Gibts da auch irgendwelche grundlegenden Überlegungen, die man sich zu dieser Neuerung machen sollte?


    Also ich verstehe hier die Frage nicht richtig, was meinst du mit grundlegenden Überlegungen? Wann man das benutzt oder wie das funktioniert oder wie?
    Lokale Funktionen und lokale Konstante Member gibt es bereits seit C# 7 das ist also alles andere als neu. Einige UseCases findest du unter Dissecting the local functions.

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

    Es ist wohl eine Frage des Geschmacks und des persönlichen Stils, ob man solch codet oder nicht.
    Ich bin kein Freund lokaler Funktionen.
    Falls Du diesen Code kopierst, achte auf die C&P-Bremse.
    Jede einzelne Zeile Deines Programms, die Du nicht explizit getestet hast, ist falsch :!:
    Ein guter .NET-Snippetkonverter (der ist verfügbar).
    Programmierfragen über PN / Konversation werden ignoriert!
    @Bluespide In den Anwendungsbeispielen fand ich zum Beispiel die Verlagerung von Exceptions oder als Alternativen zu Lambdaausdrücken.
    Das finde ich schon sehr speziell, ich meine was muss ich als Laienprogrammierer Exceptions verschieben. Könnte ja sein, dass man da pauschalere Ansichten zu formulieren kann, die auch für eingestiegene Fortgeschrittene sinnvoll in Erwägung zu ziehen sind.

    Ich dachte das wäre neu, weil der Artikel von April 2023 ist^^.
    Aber gut, aufgefallen ist es mir da ich versuche in c# zu coden und in NET 7 z.B. kein Rumpf mehr um den Mainmethodencode existieren muss. (Also bei ner neuen Konsolenanwendung steht einfach nur noch Console.Writeline("Hello World!");)
    Und alle Funktionen die man da reinschreibt, sind da automatisch solche lokalen Funktionen, obwohl man das vielleicht gar nicht so wollte

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

    Meine Permutations-Methode habe ich mal irgendwo so gemacht.

    C#-Quellcode

    1. private static IEnumerable<T[]> Permutations<T>(T[] src)
    2. {
    3. static IEnumerable<T[]> perm(int startidx, T[] data)
    4. {
    5. if (startidx == data.Length)
    6. yield return data.ToArray();
    7. for (var j = startidx; j < data.Length; j++)
    8. {
    9. (data[startidx], data[j]) = (data[j], data[startidx]);
    10. foreach (var perm in perm(startidx + 1, data))
    11. yield return perm;
    12. (data[startidx], data[j]) = (data[j], data[startidx]);
    13. }
    14. }
    15. return perm(0, src);
    16. }


    Wie man erkennen kann, geht das auch, wenn die Methoden statisch (Shared) sind. Die ganze Rekursion läuft jetzt einfach in der "lokalen Funktion" ab.

    Im Prinzip wäre das nicht nötig, denn man könnte auch Linq oder Lambda Expression nehmen. Sieht genau so gut aus.

    EDIT:
    Alternativ in Vb.Net wäre der Weg über eine Anonyme Methode, die genau so gut funktioniert.

    VB.NET-Quellcode

    1. ​Public Shared Sub Test()
    2. Dim data = Enumerable.Range(0, 4)
    3. Dim perm1 = Permutations(data)
    4. End Sub
    5. Private Shared Function Permutations(Of T)(src As IEnumerable(Of T)) As IEnumerable(Of IEnumerable(Of T))
    6. Dim perm As Func(Of IEnumerable(Of T), Int32, IEnumerable(Of IEnumerable(Of T)))
    7. perm = Function(list As IEnumerable(Of T), length As Int32)
    8. If length = 1 Then Return list.[Select](Function(t0) New T() {t0})
    9. Return perm(list, length - 1).
    10. SelectMany(Function(t0) list.Where(
    11. Function(obj) Not t0.Contains(obj)),
    12. Function(t1, t2) t1.Concat({t2}))
    13. End Function
    14. Return perm(src, src.Count)
    15. End Function


    Freundliche Grüsse

    exc-jdbi

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

    Haudruferzappeltnoch schrieb:

    Lokalen Funktionen hingegen sind definitv nicht anonym

    Korrekt. Darin liegt der große Unterschied.

    Lokale Funktionen sind immer benannt, während Lambdas (anon. Funktionen) entweder als Param übergeben oder einer Variable zugewiesen werden müssen.
    Letzten Endes erfüllen sie einen ganz ähnlichen Zweck und können für die gleichen Sachen (ge/mis)braucht werden.

    Beide kannst du z.B. als Prädikat für bedingte Schleifen/Abfragen übergeben.

    Lokale Funktionen haben den Vorteil gegenüber Lambdas, dass diese Zuweisungen auf dem Heap vermeiden können, während die für eine Lambda immer zwingend notwendig sind.
    Quellcode lizensiert unter CC by SA 2.0 (Creative Commons Share-Alike)

    Meine Firma: Procyon Systems

    Selbstständiger Softwareentwickler & IT-Techniker.

    siycah schrieb:

    während die für eine Lambda immer zwingend notwendig sind.


    Ist das so? Sicher? Lambdas können auch static sein und sollten dann nichts lokal capturen können. War das nicht auch eine Performance-Optimierung in .NET 7, dass der Compiler Lambdas die nichts capturen erkennt und das weg optimiert?

    C#-Quellcode

    1. list = list.Where(static x => x > 3).ToList();
    In dem Link von mir wird das ab UseCase 5 erklärt gezeigt.
    Der Compiler macht aus:

    C#-Quellcode

    1. static string Test()
    2. {
    3. return returnHello();
    4. string returnHello() => "Hello";
    5. }


    Das hier:

    C#-Quellcode

    1. // Token: 0x06000002 RID: 2 RVA: 0x00002054 File Offset: 0x00000254
    2. private static string Test()
    3. {
    4. return Program.<Test>g__returnHello|1_0();
    5. }
    6. // Token: 0x06000005 RID: 5 RVA: 0x000020AD File Offset: 0x000002AD
    7. [CompilerGenerated]
    8. internal static string <Test>g__returnHello|1_0()
    9. {
    10. return "Hello";
    11. }


    *Edit*

    Dissecting the local functions schrieb:


    0 heap allocations only if a lambda does not capture anything or captures a static state.

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

    Bluespide schrieb:

    Ist das so? Sicher?


    Jetzt wo ich mir die Doku selbst nochmal durchgelesen habe:

    ​Depending on their use, local functions can avoid heap allocations that are always necessary for lambda expressions. If a local function is never converted to a delegate, and none of the variables captured by the local function are captured by other lambdas or local functions that are converted to delegates, the compiler can avoid heap allocations.
    Quellcode lizensiert unter CC by SA 2.0 (Creative Commons Share-Alike)

    Meine Firma: Procyon Systems

    Selbstständiger Softwareentwickler & IT-Techniker.