Methoden

Eine Methode ist ein Codeblock, der eine Reihe von Anweisungen enthält. Ein Programm bewirkt die Ausführung der Anweisungen, indem die Methode aufgerufen wird und alle erforderlichen Methodenargumente angegeben werden. In C# werden alle Anweisungen im Kontext einer Methode ausgeführt. Die Methode Main ist der Einstiegspunkt jeder C#-Anwendung und wird von der Common Language Runtime (CLR) aufgerufen, wenn das Programm gestartet wird.

Hinweis

In diesem Thema werden benannte Methoden erläutert. Informationen über anonyme Funktionen finden Sie unter Anonyme Funktionen.

Dieses Thema enthält folgende Abschnitte:

Methodensignaturen

Methoden werden in class oder struct durch folgende Angaben deklariert:

  • Eine optionale Zugriffsebene, z.B. public oder private. Die Standardeinstellung ist private.
  • Optionale Modifizierer, z.B. abstract oder sealed.
  • Der Rückgabewert oder void, wenn die Methode keinen besitzt.
  • Der Methodenname.
  • Jede Methodenparameter. Methodenparameter werden in Klammern eingeschlossen und durch Kommas getrennt. Leere Klammern geben an, dass für die Methode keine Parameter erforderlich sind.

Diese Teile bilden zusammen die Signatur der Methode.

Hinweis

Ein Rückgabetyp einer Methode ist nicht Teil der Signatur der Methode, wenn es um die Methodenüberladung geht. Er ist jedoch Teil der Methodensignatur, wenn die Kompatibilität zwischen einem Delegaten und der Methode bestimmt wird, auf die dieser verweist.

Im folgenden Beispiel wird eine Klasse mit dem Namen Motorcycle deklariert, die fünf Methoden enthält:

using System;

abstract class Motorcycle
{
   // Anyone can call this.
   public void StartEngine() {/* Method statements here */ }

   // Only derived classes can call this.
   protected void AddGas(int gallons) { /* Method statements here */ }

   // Derived classes can override the base class implementation.
   public virtual int Drive(int miles, int speed) { /* Method statements here */ return 1; }

   // Derived classes can override the base class implementation.
   public virtual int Drive(TimeSpan time, int speed) { /* Method statements here */ return 0; }

   // Derived classes must implement this.
   public abstract double GetTopSpeed(); 
}

Beachten Sie, dass die Motorcycle-Klasse eine überladene Methode, Drive, enthält. Zwei Methoden haben denselben Namen, müssen aber durch ihre Parametertypen unterschieden werden.

Methodenaufruf

Methoden können entweder instance oder static sein. Das Aufrufen einer Instanzmethode erfordert, dass Sie ein Objekt instanziieren und die Methode an diesem Objekt aufrufen; eine Instanzmethode funktioniert in dieser Instanz und ihren Daten. Sie rufen eine statische Methode auf, indem Sie auf den Namen des Typs verweisen, zu der die Methode gehört; statische Methoden funktionieren nicht in Instanzdaten. Bei dem Versuch eine statische Methode über eine Objektinstanz aufzurufen, wird ein Compilerfehler erzeugt.

Das Aufrufen einer Methode ähnelt dem Zugreifen auf ein Feld. Fügen Sie nach dem Objektnamen (wenn Sie eine Instanzmethode aufrufen) oder dem Typnamen (beim Aufrufen einer static-Methode) einen Punkt, den Methodennamen und Klammern hinzu. Argumente werden innerhalb der Klammern aufgelistet und durch Kommas getrennt.

Die Methodendefinition gibt die Namen und Typen aller ggf. erforderlichen Parameter an. Wenn ein Aufrufer die Methode aufruft, werden für jeden Parameter konkrete Werte bereitgestellt, die als Argumente bezeichnet werden. Die Argumente müssen mit dem Parametertyp kompatibel sein, aber der Name des Arguments (sofern im aufzurufenden Code einer verwendet wird) muss nicht mit dem in der Methode definierten Parameternamen identisch sein. Im folgenden Beispiel enthält die Square-Methode einen einzelnen Parameter vom Typ int mit dem Namen i. Der erste Methodenaufruf übergibt der Square-Methode eine Variable vom Typ int mit dem Namen num. Der zweite übergibt eine numerische Konstante und der dritte einen Ausdruck.

public class Example
{
   public static void Main()
   {
      // Call with an int variable.
      int num = 4;
      int productA = Square(num);

      // Call with an integer literal.
      int productB = Square(12);

      // Call with an expression that evaulates to int.
      int productC = Square(productA * 3);
   }
   
   static int Square(int i)
   {
      // Store input argument in a local variable.
      int input = i;
      return input * input;
   }
}

Die häufigste Form des Methodenaufrufs verwendete Positionsargumente. Die Argumente werden in der gleichen Reihenfolge wie Methodenparameter bereitgestellt. Die Methoden der Motorcycle-Klasse können deshalb wie im folgenden Beispiel aufgerufen werden. Der Aufruf der Drive-Methode enthält z.B. zwei Argumente, die den beiden Parametern in der Syntax der Methode entsprechen. Das erste Argument wird der Wert des miles-Parameters, das zweite wird der Wert des speed-Parameters.

class TestMotorcycle : Motorcycle
{
   public override double GetTopSpeed()
   {
      return 108.4;
   }

   static void Main()
   {
      
      TestMotorcycle moto = new TestMotorcycle();

      moto.StartEngine();
      moto.AddGas(15);
      moto.Drive(5, 20);
      double speed = moto.GetTopSpeed();
      Console.WriteLine("My top speed is {0}", speed);            
   }
}

Sie können auch benannte Argumente anstatt Positionsargumente verwenden, wenn Sie eine Methode aufrufen. Wenn Sie benannte Argumente verwenden, geben Sie den Parameternamen, gefolgt von einem Doppelpunkt („:“), und das Argument an. Argumente können für diese Methode in beliebiger Reihenfolge erscheinen, solange alle benötigen Argumente vorhanden sind. Im folgenden Beispiel werden die benannten Argumente zum Aufrufen der TestMotorcycle.Drive-Methode verwendet. In diesem Beispiel werden die benannten Argumente in umgekehrter Reihenfolge aus der Parameterliste der Methode übergeben.

using System;

class TestMotorcycle : Motorcycle
{
   public override int Drive(int miles, int speed)
   {
      return (int) Math.Round( ((double)miles) / speed, 0);
   }

   public override double GetTopSpeed()
   {
      return 108.4;
   }

   static void Main()
   {
      
      TestMotorcycle moto = new TestMotorcycle();
      moto.StartEngine();
      moto.AddGas(15);
      var travelTime = moto.Drive(speed: 60, miles: 170);
      Console.WriteLine("Travel time: approx. {0} hours", travelTime);            
   }
}
// The example displays the following output:
//      Travel time: approx. 3 hours

Sie können eine Methode aufrufen, indem Sie sowohl Positionsargumente als auch benannte Argumente verwenden. Auf ein benanntes Argument kann jedoch kein Positionsargument folgen. Im folgenden Beispiel wird die TestMotorcycle.Drive-Methode des vorherigen Beispiels aufgerufen, indem jeweils ein Positionsargument und ein benanntes Argument verwendet wird.

var travelTime = moto.Drive(170, speed: 55);

Geerbte und überschriebene Methoden

Zusätzlich zu den Elementen, die ausdrücklich in einem Typ definiert werden, erbt ein Typ Member, die in seiner Basisklasse definiert wurden. Da alle Typen im verwalteten Typsystem direkt oder indirekt von der @System.Object-Klasse erben, erben alle Typen ihre Member, z.B. Equals(Object), GetType() und ToString(). Im folgenden Beispiel wird eine Person-Klasse definiert, zwei Person-Objekte instanziiert, und es wird die Person.Equals-Methode aufgerufen, um zu bestimmen, ob die zwei Objekte gleich sind. Jedoch ist die Equals-Methode nicht in der Person-Klasse definiert; sie wird von Object vererbt.

using System;

public class Person
{
   public String FirstName;
}

public class Example
{
   public static void Main()
   {
      var p1 = new Person();
      p1.FirstName = "John";
      var p2 = new Person();
      p2.FirstName = "John";
      Console.WriteLine("p1 = p2: {0}", p1.Equals(p2));
   }
}
// The example displays the following output:
//      p1 = p2: False

Typen können geerbte Member überschreiben, indem das Schlüsselwort override verwendet und eine Implementierung für die überschriebene Methode bereitgestellt wird. Die Signatur der Methode muss mit der überschriebenen Methode identisch sein. Das folgende Beispiel ähnelt dem vorherigen Beispiel, außer dass es die Methode @Object.Equals(System.Object) überschreibt. (Sie überschreibt auch die @Object.GetHashCode-Methode, da die zwei Methoden konsistente Ergebnisse bereitstellen sollen)

using System;

public class Person
{
   public String FirstName;

   public override bool Equals(object obj)
   {
      var p2 = obj as Person; 
      if (p2 == null)
         return false;
      else
         return FirstName.Equals(p2.FirstName);
   }

   public override int GetHashCode()
   {
      return FirstName.GetHashCode();
   } 
}

public class Example
{
   public static void Main()
   {
      var p1 = new Person();
      p1.FirstName = "John";
      var p2 = new Person();
      p2.FirstName = "John";
      Console.WriteLine("p1 = p2: {0}", p1.Equals(p2));
   }
}
// The example displays the following output:
//      p1 = p2: True

Übergeben von Parametern

Typen in C# sind entweder Werttypen oder Verweistypen. Eine Liste der integrierten Werttypen finden Sie unter Typen und Variablen. Sowohl Werttypen als auch Verweistypen werden standardmäßig als Wert an eine Methode übergeben.

Übergeben von Parametern als Wert

Wenn ein Werttyp an eine Methode als Wert übergeben wird, wird anstelle des eigentlichen Objekts standardmäßig eine Kopie übergeben. Aus diesem Grund haben Änderungen am Objekt in der aufgerufenen Methode keine Auswirkung auf das ursprüngliche Objekt, wenn das Steuerelement an den Aufrufer zurückgegeben wird.

Im folgenden Beispiel wird ein Werttyp als Wert an eine Methode übergeben, und die aufgerufene Methode versucht, den Wert des Werttyps zu ändern. Es definiert eine Variable des Typs int, die ein Werttyp ist, initialisiert seine Werte auf 20 und übergibt ihn an eine Methode mit dem Namen ModifyValue, die den Wert der Variable in 30 ändert. Wenn die Methode zurückgegeben wird, bleibt der Wert der Variable jedoch unverändert.

using System;

public class Example
{
   public static void Main()
   {
      int value = 20;
      Console.WriteLine("In Main, value = {0}", value);
      ModifyValue(value);
      Console.WriteLine("Back in Main, value = {0}", value);
   }

   static void ModifyValue(int i)
   {
      i = 30;
      Console.WriteLine("In ModifyValue, parameter value = {0}", i);
      return;
   }
}
// The example displays the following output:
//      In Main, value = 20
//      In ModifyValue, parameter value = 30
//      Back in Main, value = 20

Wenn ein Objekt eines Verweistyps als Wert an eine Methode übergeben wird, wird ein Verweis als Wert auf das Objekt übergeben. Das heißt, die Methode erhält nicht das Objekt selbst, sondern ein Argument, das den Speicherort des Objekts angibt. Wenn Sie einen Member des Objekts unter Verwendung dieses Verweises ändern, wird die Änderung im Objekt berücksichtigt, wenn das Steuerelement der aufrufenden Methode zurückgegeben wird. Jedoch hat das Ersetzen des Objekts, das an die Methode übergeben wird, keine Auswirkung auf das ursprüngliche Objekt, wenn das Steuerelement dem Aufrufer zurückgegeben wird.

Im folgenden Beispiel wird eine Klasse (die ein Verweistyp ist) mit dem Namen SampleRefType definiert. Sie instanziiert ein SampleRefType-Objekt, weist seinem value-Feld 44 zu, und übergibt das Objekt der ModifyObject-Methode. Dieses Beispiel entspricht im Wesentlichen dem vorherigen Beispiel und übergibt ein Argument als Wert an eine Methode. Da jedoch ein Verweistyp verwendet wird, unterscheidet sich das Ergebnis. Die Änderung, die in ModifyObject am obj.value-Feld vorgenommen wurden, ändern auch das value-Feld des Arguments rt in der Main-Methode auf 33, wie die Ausgabe des Beispiels zeigt.

using System;

public class SampleRefType
{
    public int value;
}

public class Example
{
    public static void Main()
    {
        var rt = new SampleRefType();
        rt.value = 44;
        ModifyObject(rt);
        Console.WriteLine(rt.value);
    }
        
    static void ModifyObject(SampleRefType obj)
    {
        obj.value = 33;
    }
}

Übergeben von Parametern durch einen Verweis

Sie übergeben einen Parameter durch einen Verweis, wenn Sie den Wert eines Arguments in einer Methode ändern möchten und diese Änderung berücksichtigen wollen, wenn das Steuerelement der aufrufenden Methode zurückgegeben wird. Verwenden Sie das Schlüsselwort ref oder out, um einen Parameter als Verweis zu übergeben.

Das folgende Beispiel ist identisch mit dem vorherigen Beispiel, außer dass der Wert durch einen Verweis an die ModifyValue-Methode übergeben wird. Wenn der Wert des Parameters in der ModifyValue-Methode verändert wird, wird die Wertänderung berücksichtigt, wenn das Steuerelement dem Aufrufer zurückgegeben wird.

using System;

public class Example
{
   public static void Main()
   {
      int value = 20;
      Console.WriteLine("In Main, value = {0}", value);
      ModifyValue(ref value);
      Console.WriteLine("Back in Main, value = {0}", value);
   }

   static void ModifyValue(ref int i)
   {
      i = 30;
      Console.WriteLine("In ModifyValue, parameter value = {0}", i);
      return;
   }
}
// The example displays the following output:
//      In Main, value = 20
//      In ModifyValue, parameter value = 30
//      Back in Main, value = 30

Ein häufiges Muster, das von ref-Parametern verwendet wird, umfasst das Tauschen der Werte der Variablen. Sie übergeben durch einen Verweis zwei Variablen an eine Methode, und die Methode tauscht deren Inhalte. Im folgenden Beispiel werden ganzzahlige Werte getauscht.

using System;

public class Example
{
   static void Main()
   {
      int i = 2, j = 3;
      System.Console.WriteLine("i = {0}  j = {1}" , i, j);

      Swap(ref i, ref j);

      System.Console.WriteLine("i = {0}  j = {1}" , i, j);
   }

   static void Swap(ref int x, ref int y)
   {
      int temp = x;
      x = y;
      y = temp;
   }   
}
// The example displays the following output:
//      i = 2  j = 3
//      i = 3  j = 2

Durch das Übergeben eines Verweistyp-Parameters können Sie den eigentlichen Wert des Verweises anstatt den Wert der einzelnen Elemente oder Felder ändern.

Parameterarrays

Manchmal ist die Voraussetzung, dass Sie die genaue Anzahl von Argumenten für Ihre Methode angeben, restriktiv. Mithilfe des Schlüsselworts params wird angegeben, dass ein Parameter ein Parameterarray ist, und Sie können Ihre Methode mit einer variablen Anzahl von Argumenten aufrufen. Der mit dem Schlüsselwort params gekennzeichnete Parameter muss ein Arraytyp sein, und er muss der letzte Parameter in der Parameterliste der Methode sein.

Ein Aufrufer kann anschließend die Methode auf drei verschiedene Arten aufrufen:

  • Durch das Übergeben eines Arrays des entsprechenden Typs, der die gewünschte Anzahl von Elementen enthält
  • Durch das Übergeben einer mit Komma getrennten Liste eines einzelnen Arguments des entsprechenden Typs der Methode
  • Durch keine Bereitstellung eines Arguments für das Parameterarray

Im folgenden Beispiel wird eine Methode mit dem Namen DoStringOperation definiert, die den Zeichenfolgevorgang ausführt, der von dessen erstem Parameter – einem StringOperation-Enumerationsmember – angegeben wurde. Die Zeichenfolge, von der der Vorgang ausgeführt wird, wird durch ein Parameterarray definiert. Die Main-Methode zeigt alle drei Möglichkeiten, um die Methode aufzurufen. Beachten Sie, dass die mit Schlüsselwort params gekennzeichnete Methode auf den Fall vorbereitet werden muss, in dem kein Argument für das Parameterarray bereitgestellt wird, sodass sein Wert null entspricht.

using System;

class Example 
{
    static void Main() 
    {
        int[] arr = {1, 4, 5};
        Console.WriteLine("In Main, array has {0} elements and starts with {1}",
                          arr.Length, arr[0]);

        Change(ref arr);
        Console.WriteLine("Back in Main, array has {0} elements and starts with {1}",
                          arr.Length, arr[0]);
    }

    static void Change(ref int[] arr)
    {
        // Both of the following changes will affect the original variables:
        arr = new int[5] {-9, -7, -5, -3, -1};
        Console.WriteLine("In Change, array has {0} elements and starts with {1}",
                          arr.Length, arr[0]);
    }
}
// The example displays the following output:
//        In Main, array has 3 elements and starts with 1
//        In Change, array has 5 elements and starts with -9
//        Back in Main, array has 5 elements and starts with -9

Optionale Parameter und Argumente

Eine Methodendefinition kann angeben, dass seine Parameter erforderlich oder optional sind. Parameter sind standardmäßig erforderlich. Optionale Parameter werden einschließlich des Standardwerts des Parameters in der Methodendefinition angegeben. Wird die Methode aufgerufen, wenn kein Argument für einen optionalen Parameter angegeben wird, wird stattdessen der Standardwert verwendet.

Der Standardwert des Parameters muss von einer der folgenden Ausdrucksarten zugewiesen werden:

  • Eine Konstante, z.B. eine Zeichenfolgenliteral oder eine Zahl
  • Ein Ausdruck in Form von new ValType, wobei ValType ein Werttyp ist. Beachten Sie, dass dies den impliziten Standardkonstruktor des Werttyps aufruft, der eigentlich kein Member des Typs ist.
  • Ein Ausdruck in Form von default(ValType), wobei ValType ein Werttyp ist

Wenn eine Methode erforderliche und optionale Parameter enthält, werden optionale Parameter nach allen benötigten Parametern am Ende der Parameterliste definiert.

Im folgenden Beispiel wird eine ExampleMethod-Methode definiert, die aus einem erforderlichen und zwei optionalen Parametern besteht.

using System;

public class Options
{
   public void ExampleMethod(int required, int optionalInt = default(int),
                             string description = "Optional Description")
   {
      Console.WriteLine("{0}: {1} + {2} = {3}", description, required, 
                        optionalInt, required + optionalInt);
   }
}

Wenn eine Methode mit mehreren optionalen Argumenten mithilfe von Positionsargumenten aufgerufen wird, muss der Aufrufer ein Argument für alle optionalen Parameter, vom ersten bis zum letzten, bereitstellen, für die ein Argument bereitgestellt wird. Bei der ExampleMethod-Methode muss der Parameter z.B. auch ein Argument für den description-Parameter bereitstellen, wenn er ein Argument für den optionalInt-Parameter bereitstellt. opt.ExampleMethod(2, 2, "Addition of 2 and 2"); ist ein gültiger Methodenaufruf; opt.ExampleMethod(2, , "Addition of 2 and 0); erzeugt einen Compilerfehler: „Argument fehlt“.

Wenn eine Methode durch ein benanntes Argument oder einer Mischung aus benannten und Positionsargumenten aufgerufen wird, kann der Aufrufer Argumente auslassen, die dem letzten Positionsargument im Methodenaufruf folgen.

Im folgenden Beispiel wird die ExampleMethod-Methode dreimal aufgerufen. Die ersten zwei Methodenaufrufe verwenden Positionsargumente. Der erste Methodenaufruf lässt beide optionale Argumente aus, während der Zweite das letzte Argument auslässt. Der dritte Methodenaufruf stellt für die benötigten Parameter ein Positionsargument bereit, verwendet aber ein benanntes Argument, um einen Wert für den description-Parameter bereitzustellen, während das optionalInt-Argument ausgelassen wird.

public class Example
{
   public static void Main()
   {
      var opt = new Options();
      opt.ExampleMethod(10);
      opt.ExampleMethod(10, 2);
      opt.ExampleMethod(12, description: "Addition with zero:");
   }
} 
// The example displays the following output:
//      Optional Description: 10 + 0 = 10
//      Optional Description: 10 + 2 = 12
//      Addition with zero:: 12 + 0 = 12

Die Verwendung von zwei optionalen Parametern wirkt sich auf die Überladungsauflösung aus, oder die Art und Weise, mit der der C#-Compiler bestimmt, welche besondere Überladung von einem Methodenaufruf wie folgt aufgerufen werden sollte:

  • Eine Methode, ein Indexer oder ein Konstruktor ist ein Kandidat für die Ausführung, wenn jeder der Parameter entweder optional ist oder über Namen oder Position auf ein einzelnes Argument in der aufrufenden Anweisung reagiert. Dieses Argument kann in dem Typ des Parameters konvertiert werden.
  • Wenn mehr als ein Kandidat gefunden wird, werden die Regeln der Überladungsauflösung als bevorzugte Konvertierungen auf die Argumente angewandt, die ausdrücklich angegeben sind. Ausgelassene Argumente für optionale Parameter werden ignoriert.
  • Wenn zwei Kandidaten gleich gut geeignet sind, wird ein Kandidat bevorzugt, der keine optionalen Parameter besitzt, für die Argumente im Aufruf ausgelassen wurden. Dies ist die Folge einer allgemeinen Präferenz bei der Überladungsauflösung für Kandidaten, die weniger Parameter besitzen.

Rückgabewert

Methoden können einen Wert an die aufrufende Funktion (den Aufrufer) zurückgeben. Wenn der Rückgabetyp (der vor dem Methodennamen aufgeführte Typ) nicht void ist, kann die Methode den Wert mithilfe des return-Schlüsselworts zurückgeben. Eine Anweisung mit dem Schlüsselwort return, gefolgt von einem Wert, der dem Rückgabetyp entspricht, gibt diesen Wert an den Methodenaufrufer zurück. Methoden mit einem anderen Rückgabetyp als „void“ müssen das return -Schlüsselwort verwenden, um einen Wert zurückzugeben. Das return -Schlüsselwort beendet außerdem die Ausführung der Methode.

Wenn der Rückgabetyp voidist, ist eine return -Anweisung ohne Wert immer noch nützlich, um die Ausführung der Methode zu beenden. Ohne das return -Schlüsselwort wird die Ausführung der Methode beendet, wenn das Ende des Codeblocks erreicht ist.

Die folgenden beiden Methoden verwenden z. B. das return -Schlüsselwort, um ganze Zahlen zurückzugeben:

class SimpleMath
{
    public int AddTwoNumbers(int number1, int number2)
    {
        return number1 + number2;
    }

    public int SquareANumber(int number)
    {
        return number * number;
    }
}

Um einen von einer Methode zurückgegebenen Wert zu verwenden, kann die aufrufende Methode den Methodenaufruf selbst an jeder Stelle verwenden, an der ein Wert des gleichen Typs ausreichend ist. Sie können den Rückgabewert auch einer Variablen zuweisen. Beispielsweise wird mit den folgenden beiden Codebeispiele das gleiche Ergebnis erzielt:

int result = obj.AddTwoNumbers(1, 2);
result = obj.SquareANumber(result);
// The result is 9.
Console.WriteLine(result);
result = obj.SquareANumber(obj.AddTwoNumbers(1, 2));
// The result is 9.
Console.WriteLine(result);

Die Verwendung einer lokalen Variablen, in diesem Fall result, zum Speichern eines Werts ist optional. Es kann die Lesbarkeit des Codes verbessern, oder es kann notwendig sein, wenn Sie den ursprünglichen Wert des Arguments für den gesamten Gültigkeitsbereich der Methode speichern müssen.

Manchmal möchten Sie, dass Ihre Methode mehr als einen Wert zurückgibt. Ab mit C#-7.0 können Sie dies einfach mithilfe von Tupeltypen und Tupelliteralen erledigen. Der Tupeltyp definiert die Datentypen der Elemente des Tupels. Tupelliterale stellen die tatsächlichen Werte des zurückgegebenen Tupels bereit. Im folgenden Beispiel definiert (string, string, string, int) den Tupeltyp, der durch die GetPersonalInfo-Methode zurückgegeben wird. Der (per.FirstName, per.MiddleName, per.LastName, per.Age)-Ausdruck ist das Tupelliteral. Die Methode gibt den ersten, mittleren und letzten Namen zusammen mit dem Alter eines PersonInfo-Objekts zurück.

public (string, string, string, int) GetPersonalInfo(string id)
{
    PersonInfo per = PersonInfo.RetrieveInfoById(id);
    if (per != null)
       return (per.FirstName, per.MiddleName, per.LastName, per.Age);
    else
       return null;
}

Der Aufrufer kann anschließend das zurückgegebene Tupel mit Code wie dem folgenden verwenden:

var person = GetPersonalInfo("111111111")
if (person != null)
   Console.WriteLine("{person.Item1} {person.Item3}: age = {person.Item4}");

Namen können auch den Tupelelementen in der Typdefinition des Tupels zugewiesen werden. Das folgende Beispiel zeigt eine alternative Version der GetPersonalInfo-Methode, die benannte Elemente verwendet:

public (string FName, string MName, string LName, int Age) GetPersonalInfo(string id)
{
    PersonInfo per = PersonInfo.RetrieveInfoById(id);
    if (per != null)
       return (per.FirstName, per.MiddleName, per.LastName, per.Age);
    else
       return null;
}

Der vorherige Aufruf der GetPersonInfo-Methode kann anschließend wie folgt geändert werden:

var person = GetPersonalInfo("111111111");
if (person != null)
   Console.WriteLine("{person.FName} {person.LName}: age = {person.Age}");

Wenn eine Methode einem Array als Argument übergeben wird und den Wert der einzelnen Elemente ändert, ist es nicht erforderlich, dass die Methode das Array zurückgibt, obwohl Sie sich entscheiden könnten, dies für den funktionalen Fluss von Werten oder zu stilistischen Zwecken zu tun. Das liegt daran, dass C# alle Verweistypen als Wert übergibt und der Wert eines Arrayverweises der Zeiger auf das Array ist. Im folgenden Beispiel sind Änderungen an den Inhalten des values-Arrays, die in der DoubleValues-Methode ausgeführt werden, von jedem Code beobachtbar, der einen Verweis auf das Array hat.



using System;

public class Example
{
   static void Main(string[] args)  
   {  
      int[] values = { 2, 4, 6, 8 };
      DoubleValues(values);
      foreach (var value in values)
         Console.Write("{0}  ", value);
   }  
  
   public static void DoubleValues(int[] arr)
   {
      for (int ctr = 0; ctr <= arr.GetUpperBound(0); ctr++)
         arr[ctr] = arr[ctr] * 2;
   }
}
// The example displays the following output:
//       4  8  12  16

Erweiterungsmethoden

Es gibt normalerweise zwei Möglichkeiten, einem vorhandenen Typ eine Methode hinzuzufügen:

  • Ändern Sie den Quellcode für diesen Typ. Sie können dies natürlich nicht tun, wenn Sie nicht den Quellcode des Typs besitzen. Dies wird zudem eine bahnbrechende Änderung, wenn Sie auch private Datenfelder zur Unterstützung der Methode hinzufügen.
  • Definieren Sie die neue Methode in einer abgeleiteten Klasse. Eine Methode kann nicht auf diese Weise für andere Typen wie Strukturen oder Enumerationen mithilfe von Vererbung hinzugefügt werden. Sie kann auch nicht verwendet werden, um einer versiegelten Klasse eine Methode „hinzuzufügen“.

Erweiterungsmethoden lassen Sie eine Methode einem vorhanden Typ „hinzufügen“, ohne den eigentlichen Typ zu verändern oder die neue Methode in einem geerbten Typ zu implementieren. Die Erweiterungsmethode muss sich auch nicht im gleichen Assembly wie der Typ befinden, den es erweitert. Sie rufen eine Erweiterungsmethode auf, als ob es sich um einen definierten Member eines Typs handele.

Weitere Informationen finden Sie unter Erweiterungsmethoden.

Asynchrone Methoden

Mithilfe der Async-Funktion können Sie asynchrone Methoden aufrufen, ohne explizite Rückrufe verwenden oder den Code manuell über mehrere Methoden oder Lambda-Ausdrücke teilen zu müssen.

Wenn Sie eine Methode mit dem Modifizierer async kennzeichnen, können Sie den Operator await in der Methode verwenden. Wenn ein await-Ausdruck in der asynchronen Methode erreicht wird, wird die Steuerung an den Aufrufer zurückgegeben, wenn die erwartete Aufgabe nicht fertig ist, und die Ausführung der Methode mit dem Schlüsselwort await wird angehalten, bis die erwartete Aufgabe abgeschlossen ist. Wenn die Aufgabe abgeschlossen ist, kann die Ausführung in der Methode fortgesetzt werden.

Hinweis

Eine asynchrone Methode wird an den Aufrufer zurückgegeben, wenn sie entweder auf das erste erwartete Objekt trifft, das noch nicht abgeschlossen wurde, oder das Ende der asynchronen Methode erreicht.

Eine asynchrone Methode kann den Rückgabetyp @System.Threading.Tasks.Task<TResult>, Task oder void haben. Der Rückgabetyp void wird hauptsächlich zum Definieren von Ereignishandlern verwendet, wobei ein void-Rückgabetyp erforderlich ist. Auf eine asynchrone Methode, die void zurückgibt, kann nicht gewartet werden, und der Aufrufer einer Methode mit void-Rückgabe kann keine Ausnahmen abfangen, die die Methode auslöst. Mit der Veröffentlichung von C# 7 wird es diese Einschränkung gelockert, damit eine asynchrone Methode jeden aufgabenähnlichen Typ zurückgeben kann.

Im folgenden Beispiel ist DelayAsync eine asynchrone Methode, die eine Rückgabeanweisung besitzt, die eine ganze Zahl zurückgibt. Da es sich um eine async-Methode handelt, muss die Methodendeklaration einen Task<int>-Rückgabetyp haben. Da der Rückgabetyp Task<int> ist, ergibt die Auswertung des await-Ausdrucks in DoSomethingAsync eine ganze Zahl, wie die folgende int result = await delayTask-Anweisung veranschaulicht.

using System;
using System.Diagnostics;
using System.Threading.Tasks;

public class Example
{
    // This Click event is marked with the async modifier.
    public static void Main()
    {
       DoSomethingAsync().Wait();
    }

    private static async Task DoSomethingAsync()
    {
        int result = await DelayAsync();
        Console.WriteLine("Result: " + result);
    }

    private static async Task<int> DelayAsync()
    {
        await Task.Delay(100);
        return 5;
    }

    // Output:
    //  Result: 5
}
// The example displays the following output:
//        Result: 5

Mit einer asynchronen Methode können keine ref- oder out-Parameter deklariert, jedoch Methoden aufgerufen werden, die solche Parameter aufweisen.

Weitere Informationen über asynchrone Methoden finden Sie unter Asynchronous Programming with async and await (Asynchrone Programmierung mit Async und Await), Ablaufsteuerung in asynchronen Programmen und Asynchrone Rückgabetypen.

Ausdruckskörpermember

Es gibt häufig Methodendefinitionen, die einfach direkt das Ergebnis eines Ausdrucks zurückgeben oder eine einzige Anweisung als Text der Methode aufweisen. Es ist eine Syntaxabkürzung zur Definition solcher Methoden mithilfe von =>verfügbar:


public Point Move(int dx, int dy) => new Point(x + dx, y + dy);
public void Print() => Console.WriteLine(First + " " + Last);
// Works with operators, properties, and indexers too.
public static Complex operator +(Complex a, Complex b) => a.Add(b);
public string Name => First + " " + Last;
public Customer this[long id] => store.LookupCustomer(id);

Wenn die Methode void zurückgibt oder es sich um eine asynchrone Methode handelt, muss der Text der Methode ein Anweisungsausdruck sein (wie bei Lambdas). Eigenschaften und Indexer müssen schreibgeschützt sein. Verwenden Sie darüber hinaus nicht das get-Accessorschlüsselwort.

Iteratoren

Ein Iterator führt eine benutzerdefinierte Iteration durch eine Auflistung durch, z. B. eine Liste oder ein Array. Ein Iterator verwendet die Anweisung yield return, um jedes Element einzeln nacheinander zurückzugeben. Wenn eine yield return-Anweisung erreicht wird, wird die aktuelle Position gespeichert, sodass der Aufrufer das nächste Element in der Sequenz anfordern kann.

Der Rückgabetyp eines Iterators kann IEnumerable, IEnumerable<T>, IEnumerator oder IEnumerator<T> sein.

Weitere Informationen finden Sie unter Iteratoren.

Siehe auch

Zugriffsmodifizierer Statische Klassen und statische Klassenmember Vererbung Abstrakte und versiegelte Klassen und Klassenmember Params out ref Übergeben von Parametern