So erstellen Sie Inline-Funktionen in C #

91

Ich verwende Linq To XML

new XElement("Prefix", Prefix == null ? "" : Prefix)

Ich möchte jedoch einige Berechnungen für das Präfix durchführen, bevor ich es der XML-Datei hinzufüge, z. B. Leerzeichen, Sonderzeichen, einige Berechnungen usw.

Ich möchte keine Funktionen erstellen, da diese für keinen anderen Teil meines Programms hilfreich sind. Gibt es also eine Möglichkeit, Inline-Funktionen zu erstellen?

Joe Dixon
quelle
4
Verbieten Sie sich nicht, eine Funktion zu erstellen, nur weil sie von keinem anderen Ort aus aufgerufen wird. Funktionen können auch verwendet werden, um den Code zu bereinigen (wenn Sie eine große Prozedur haben, die mehrere Seiten umfasst und ihn in Funktionen aufteilt, wird er besser lesbar) und selbst zu dokumentieren (nur eine Funktion richtig zu benennen, kann dem Leser Informationen übermitteln.)
Joe
9
Wenn Sie von Google hierher gekommen sind und wissen möchten, wie Inline-Funktionen in c # emuliert werden, klicken Sie hier: stackoverflow.com/questions/473782/inline-functions-in-c Die folgenden Antworten beziehen sich nicht auf "Inline" -Funktionen im wahrsten Sinne des Wortes, und c # hat nicht einmal echte Inline-Funktionen, aber der obige Link bietet eine Compiler-Optimierung, die verwendet werden kann.
JamesHoux
Danke James, der Titel der Frage ist in der Tat ziemlich irreführend.
Zar Shardan

Antworten:

218

Ja, C # unterstützt das. Es stehen verschiedene Syntaxen zur Verfügung.

  • In C # 2.0 wurden anonyme Methoden hinzugefügt:

    Func<int, int, int> add = delegate(int x, int y)
    {
        return x + y;
    };
    Action<int> print = delegate(int x)
    {
        Console.WriteLine(x);
    }
    Action<int> helloWorld = delegate // parameters can be elided if ignored
    {
        Console.WriteLine("Hello world!");
    }
  • Lambdas sind neu in C # 3.0 und in zwei Geschmacksrichtungen erhältlich.

    • Ausdruck Lambdas:

      Func<int, int, int> add = (int x, int y) => x + y; // or...
      Func<int, int, int> add = (x, y) => x + y; // types are inferred by the compiler
    • Aussage Lambdas:

      Action<int> print = (int x) => { Console.WriteLine(x); };
      Action<int> print = x => { Console.WriteLine(x); }; // inferred types
      Func<int, int, int> add = (x, y) => { return x + y; };
  • Lokale Funktionen wurden mit C # 7.0 eingeführt:

    int add(int x, int y) => x + y;
    void print(int x) { Console.WriteLine(x); }

Grundsätzlich gibt es zwei verschiedene Typen für diese: Funcund Action. Funcs Rückgabewerte, aber Actionnicht. Der letzte Typparameter von a Funcist der Rückgabetyp. Alle anderen sind die Parametertypen.

Es gibt ähnliche Typen mit unterschiedlichen Namen, aber die Syntax für die Inline-Deklaration ist dieselbe. Ein Beispiel hierfür ist Comparison<T>, was in etwa gleichbedeutend ist mit Func<T, T, int>.

Func<string, string, int> compare1 = (l,r) => 1;
Comparison<string> compare2 = (l, r) => 1;
Comparison<string> compare3 = compare1; // this one only works from C# 4.0 onwards

Diese können direkt aufgerufen werden, als wären sie reguläre Methoden:

int x = add(23, 17); // x == 40
print(x); // outputs 40
helloWorld(x); // helloWorld has one int parameter declared: Action<int>
               // even though it does not make any use of it.
R. Martinho Fernandes
quelle
3
Ich verstehe diese Antwort nicht. In seinem Beispiel möchte er, dass neues XElement ("Präfix", Präfix => newPrefix) inline deklariert wird. Alle diese Antworten bedeuten, eine neue Funktion zu deklarieren. Warum nicht einfach eine neue Funktion deklarieren?
Matthew James Davis
2
weil: 1. die Logik des Lesens von Inline-Funktionen zu verstehen ist viel einfacher als das Durchsuchen verschiedener Deklarationen 2. häufig müssen Sie weniger Code schreiben, wenn Sie Inline-Funktionen verwenden
Volodymyr
35

C # 7 bietet Unterstützung für lokale Funktionen

Hier ist das vorherige Beispiel mit einer lokalen Funktion

void Method()
{
    string localFunction(string source)
    {
        // add your functionality here
        return source ;
    };

   // call the inline function
   localFunction("prefix");
}
DalSoft
quelle
26

Die Antwort auf Ihre Frage lautet Ja und Nein, je nachdem, was Sie unter "Inline-Funktion" verstehen. Wenn Sie den Begriff wie in der C ++ - Entwicklung verwenden, lautet die Antwort Nein, das können Sie nicht - selbst ein Lambda-Ausdruck ist ein Funktionsaufruf. Zwar können Sie Inline-Lambda-Ausdrücke definieren, um Funktionsdeklarationen in C # zu ersetzen, doch der Compiler erstellt dennoch eine anonyme Funktion.

Hier ist ein wirklich einfacher Code, mit dem ich dies getestet habe (VS2015):

    static void Main(string[] args)
    {
        Func<int, int> incr = a => a + 1;
        Console.WriteLine($"P1 = {incr(5)}");
    }

Was generiert der Compiler? Ich habe ein nützliches Tool namens ILSpy verwendet, das die tatsächlich generierte IL-Assembly anzeigt. Schauen Sie mal rein (ich habe viele Sachen zum Einrichten von Klassen weggelassen)

Dies ist die Hauptfunktion:

        IL_001f: stloc.0
        IL_0020: ldstr "P1 = {0}"
        IL_0025: ldloc.0
        IL_0026: ldc.i4.5
        IL_0027: callvirt instance !1 class [mscorlib]System.Func`2<int32, int32>::Invoke(!0)
        IL_002c: box [mscorlib]System.Int32
        IL_0031: call string [mscorlib]System.String::Format(string, object)
        IL_0036: call void [mscorlib]System.Console::WriteLine(string)
        IL_003b: ret

Sehen Sie diese Zeilen IL_0026 und IL_0027? Diese beiden Anweisungen laden die Nummer 5 und rufen eine Funktion auf. Dann formatieren und drucken IL_0031 und IL_0036 das Ergebnis.

Und hier ist die Funktion namens:

        .method assembly hidebysig 
            instance int32 '<Main>b__0_0' (
                int32 a
            ) cil managed 
        {
            // Method begins at RVA 0x20ac
            // Code size 4 (0x4)
            .maxstack 8

            IL_0000: ldarg.1
            IL_0001: ldc.i4.1
            IL_0002: add
            IL_0003: ret
        } // end of method '<>c'::'<Main>b__0_0'

Es ist eine sehr kurze Funktion, aber es ist eine Funktion.

Lohnt sich die Optimierung? Nein, nein. Wenn Sie es tausende Male pro Sekunde aufrufen, aber wenn die Leistung so wichtig ist, sollten Sie in Betracht ziehen, nativen Code aufzurufen, der in C / C ++ geschrieben ist, um die Arbeit zu erledigen.

Nach meiner Erfahrung sind Lesbarkeit und Wartbarkeit fast immer wichtiger als die Optimierung für einige Mikrosekunden Geschwindigkeitsgewinn. Verwenden Sie Funktionen, um Ihren Code lesbar zu machen und den Gültigkeitsbereich von Variablen zu steuern, und sorgen Sie sich nicht um die Leistung.

"Vorzeitige Optimierung ist die Wurzel allen Übels (oder zumindest des größten Teils davon) in der Programmierung." - Donald Knuth

"Ein Programm, das nicht richtig läuft, muss nicht schnell laufen" - Ich

Ray Fischer
quelle
1
Dies ist ein Top-Google-Hit für das Inlining von C # -Funktionen. Sie sagen "Vielleicht, wenn Sie es tausende Male pro Sekunde aufrufen" und raten Sie mal - ich nenne es 4 Millionen Mal pro Sekunde, also ja ... Inlining wäre wahrscheinlich nützlich (und würde die Lesbarkeit von Code im Vergleich zu was erheblich verbessern Ich muss gleich tun: manuelles Abrollen einer Funktion an 16 Stellen).
Adam
17

Ja.

Sie können anonyme Methoden oder Lambda-Ausdrücke erstellen :

Func<string, string> PrefixTrimmer = delegate(string x) {
    return x ?? "";
};
Func<string, string> PrefixTrimmer = x => x ?? "";
SLaks
quelle
Vielen Dank für Ihre Antwort. Könnten Sie die Antwort etwas näher erläutern, die Lamba, ich meine die codeFunc <string, string> PrefixTrimmer = x => x? ""; codeIch bin neu in diesem und ich verstehe das MSDN-Dokument wirklich nicht sehr gut
Joe Dixon
2
@ Joe: x ?? ""ist der Null-Koaleszenz-Operator. msdn.microsoft.com/en-us/library/ms173224.aspx
SLaks
In x => (something), xist ein Parameter, und (something)ist die Rückkehr value`.
SLaks
1
@Hellfrost: Lies die Frage. Er fragt nicht nach Inline-Funktionen im C ++ - Stil. Ich möchte keine Funktionen erstellen, da diese für keinen anderen Teil meines Programms als diese
hilfreich sind
5

Sie können Func verwenden, das eine Methode mit einem Parameter kapselt und einen Wert des vom Parameter TResult angegebenen Typs zurückgibt.

void Method()
{
    Func<string,string> inlineFunction = source => 
    {
        // add your functionality here
        return source ;
     };


    // call the inline function
   inlineFunction("prefix");
}
Homam
quelle
4

Es kann nicht nur Inside-Methoden verwenden, sondern auch innerhalb von Klassen.

class Calculator
    {
        public static int Sum(int x,int y) => x + y;
        public static Func<int, int, int>  Add = (x, y) => x + y;
        public static Action<int,int> DisplaySum = (x, y) => Console.WriteLine(x + y);
    }
Deepak Mishra
quelle