Implementieren von Klassenmethoden und -parametern
Eine Methode ist ein Codeblock, der eine Reihe von Anweisungen enthält. Ein Programm bewirkt, dass die Anweisungen ausgeführt werden, indem die Methode aufgerufen und alle erforderlichen Methodenargumente angegeben werden. In C# wird jede ausgeführte Anweisung im Kontext einer Methode ausgeführt.
Methodensignaturen
Methoden werden in einer Klasse, einem Datensatz oder einer Struktur deklariert, indem Folgendes angegeben wird:
- Eine optionale Zugriffsebene, z. B.
publicoderprivate. Der Standardwert istprivate. - Optionale Modifizierer wie
abstractodersealed. - Der Rückgabewert oder
void, wenn die Methode keine hat. - Der Methodenname.
- Alle Methodenparameter. Methodenparameter werden in Klammern eingeschlossen und durch Kommas getrennt. Leere Klammern deuten darauf hin, dass für die Methode keine Parameter erforderlich sind.
Diese Teile arbeiten zusammen, um die Methodensignatur zu bilden.
Wichtig
Ein Rückgabetyp einer Methode ist nicht Teil der Signatur der Methode für die Zwecke der Methodenüberladung. Es ist jedoch Teil der Signatur der Methode, wenn die Kompatibilität zwischen einem Delegaten und der Methode bestimmt wird, auf die sie verweist.
Im folgenden Beispiel wird eine Klasse namens Motorcycle definiert, die fünf Methoden enthält:
namespace MotorCycleExample
{
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();
}
}
Die Motorcycle Klasse enthält eine überladene Methode, Drive. Die beiden Drive Methoden haben denselben Namen, aber unterschiedliche Parametertypen.
Methodenaufruf
Methoden können entweder Instanz oder statischensein. Sie müssen ein Objekt instanziieren, um eine Instanzmethode für diese Instanz aufzurufen; eine Instanzmethode wird für diese Instanz und deren Daten ausgeführt. Sie rufen eine statische Methode auf, indem Sie auf den Namen des Typs verweisen, zu dem die Methode gehört; Statische Methoden funktionieren nicht mit Instanzdaten. Beim Versuch, eine statische Methode über eine Objektinstanz aufzurufen, wird ein Compilerfehler generiert.
Das Aufrufen einer Methode ähnelt dem Zugriff auf ein Feld. Fügen Sie nach dem Objektnamen (wenn Sie eine Instanzmethode aufrufen) oder dem Typnamen (wenn Sie eine statische Methode aufrufen) einen Punkt, den Namen der Methode und Klammern hinzu. Argumente werden innerhalb der Klammern aufgelistet und durch Kommas getrennt.
Die Methodendefinition gibt die Namen und Typen aller erforderlichen Parameter an. Wenn ein Aufrufer die Methode aufruft, stellt er für jeden Parameter konkrete Werte bereit, die als Argumente bezeichnet werden. Die Argumente müssen mit dem Parametertyp kompatibel sein, aber der Argumentname muss, wenn ein Argument im aufrufenden Code verwendet wird, nicht mit dem in der Methode definierten Parameter identisch sein. Im folgenden Beispiel enthält die Square-Methode einen einzelnen Parameter vom Typ int namens i. Der erste Methodenaufruf übergibt die Square Methode eine Variable vom Typ int namens num; die zweite, eine numerische Konstante; und der dritte, ein Ausdruck.
public static class SquareExample
{
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 evaluates 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;
}
}
Wert- und Referenzparameter
Typen in C# sind entweder Werttypen oder Verweistypen. Standardmäßig werden sowohl Werttypen als auch Verweistypen an eine Methode übergeben.
Werttypparameter
Wenn ein Werttyp nach Wert an eine Methode übergeben wird, wird eine Kopie des Objekts anstelle des Objekts selbst an die Methode übergeben. Daher haben Änderungen am Objekt in der aufgerufenen Methode keine Auswirkungen auf das ursprüngliche Objekt, wenn das Steuerelement an den Aufrufer zurückkehrt.
Im folgenden Beispiel wird ein Werttyp nach Wert an eine Methode übergeben, und die aufgerufene Methode versucht, den Wert des Werttyps zu ändern. Sie definiert eine Variable vom Typ int, bei der es sich um einen Werttyp handelt, dessen Wert auf 20 initialisiert wird, und übergibt sie an eine Methode mit dem Namen ModifyValue, die den Wert der Variablen in 30 ändert. Wenn die Methode jedoch zurückgegeben wird, bleibt der Wert der Variablen unverändert.
public static class ByValueExample
{
public static void Main()
{
var 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 an eine Methode nach Wert übergeben wird, wird ein Verweis auf das Objekt nach Wert übergeben. Das heißt, die Methode empfängt nicht das Objekt selbst, sondern ein Argument, das die Position des Objekts angibt. Wenn Sie ein Element des Objekts mithilfe dieses Verweises ändern, wird die Änderung im Objekt wiedergegeben, wenn das Steuerelement zur aufrufenden Methode zurückkehrt. Das Ersetzen des an die Methode übergebenen Objekts hat jedoch keine Auswirkungen auf das ursprüngliche Objekt, wenn das Steuerelement an den Aufrufer zurückgegeben wird.
Im folgenden Beispiel wird eine Klasse (ein Bezugstyp) mit dem Namen SampleRefTypedefiniert. Es instanziiert ein SampleRefType-Objekt, weist dem value Feld 44 zu und übergibt das Objekt an die ModifyObject-Methode. In diesem Beispiel wird im Wesentlichen dasselbe ausgeführt wie im vorherigen Beispiel (es übergibt ein Argument nach Wert an eine Methode). Das Ergebnis unterscheidet sich jedoch, da ein Bezugstyp anstelle eines Werttyps verwendet wird. Die Änderung, die in ModifyObject am Feld obj.value vorgenommen wird, ändert auch das value Feld des Arguments, rt. Wenn die Main-Methode den Wert von rt wird angezeigt, dass sie auf 33 aktualisiert wurde, wie die Ausgabe aus dem Beispiel zeigt.
public class SampleRefType
{
public int value;
}
public static class ByRefTypeExample
{
public static void Main()
{
var rt = new SampleRefType { value = 44 };
Console.WriteLine("In Main, rt.value = {0}", rt.value);
ModifyObject(rt);
Console.WriteLine("Back in Main, rt.value = {0}", rt.value);
}
static void ModifyObject(SampleRefType obj)
{
obj.value = 33;
Console.WriteLine("In ModifyObject, obj.value = {0}", obj.value);
}
}
// The example displays the following output:
// In Main, rt.value = 44
// In ModifyObject, obj.value = 33
// Back in Main, rt.value = 33
Referenztypparameter
Sie übergeben einen Parameter anhand eines Verweises, wenn Sie den Wert eines Arguments in einer Methode ändern möchten und diese Änderung wiedergeben möchten, wenn das Steuerelement zur aufrufenden Methode zurückkehrt. Um einen Parameter anhand eines Verweises zu übergeben, verwenden Sie das Schlüsselwort ref oder out. Sie können auch einen Wert durch Verweis übergeben, um das Kopieren zu vermeiden, aber dennoch Änderungen mithilfe des schlüsselworts in verhindern.
Das folgende Beispiel ist mit dem vorherigen identisch, mit ausnahme des Werts, der durch Verweis auf die ModifyValue-Methode übergeben wird. Wenn der Wert des Parameters in der ModifyValue-Methode geändert wird, wird die Wertänderung angezeigt, wenn das Steuerelement an den Aufrufer zurückgibt.
public static class ByRefExample
{
public static void Main()
{
var value = 20;
Console.WriteLine("In Main, value = {0}", value);
ModifyValue(ref value);
Console.WriteLine("Back in Main, value = {0}", value);
}
private 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 gängiges Muster, das von Bezugsparametern verwendet wird, umfasst das Austauschen der Werte von Variablen. Sie übergeben zwei Variablen anhand eines Verweises an eine Methode, und die Methode tauscht deren Inhalte aus. Im folgenden Beispiel werden ganzzahlige Werte ausgetauscht.
public static class RefSwapExample
{
static void Main()
{
int i = 2, j = 3;
Console.WriteLine("i = {0} j = {1}", i, j);
Swap(ref i, ref j);
Console.WriteLine("i = {0} j = {1}", i, j);
}
static void Swap(ref int x, ref int y) =>
(y, x) = (x, y);
}
// The example displays the following output:
// i = 2 j = 3
// i = 3 j = 2
Durch Übergeben eines Referenztypparameters können Sie den Wert des Verweises selbst und nicht den Wert der einzelnen Elemente oder Felder ändern.
Parameterauflistungen
Manchmal ist die Anforderung, dass Sie die genaue Anzahl von Argumenten für Ihre Methode angeben, restriktiv. Wenn Sie das schlüsselwort params verwenden, um anzugeben, dass ein Parameter eine Parameterauflistung ist, können Sie die Methode mit einer variablen Anzahl von Argumenten aufrufen. Der parameter, der mit dem Schlüsselwort params markiert ist, muss ein Sammlungstyp sein, und er muss der letzte Parameter in der Parameterliste der Methode sein.
Ein Aufrufer kann die Methode dann auf vier Arten für den Parameter Params aufrufen:
- Durch Übergeben einer Auflistung des entsprechenden Typs, die die gewünschte Anzahl von Elementen enthält. Im Beispiel wird ein Auflistungsausdruck verwendet, sodass der Compiler einen geeigneten Auflistungstyp erstellt.
- Durch Übergeben einer durch Trennzeichen getrennten Liste einzelner Argumente des entsprechenden Typs an die Methode. Der Compiler erstellt den entsprechenden Sammlungstyp.
- Durch Übergeben
null. - Durch keine Angabe eines Arguments für die Parameterauflistung.
Im folgenden Beispiel wird eine Methode mit dem Namen GetVowels definiert, die alle Vokale aus einer Parameterauflistung zurückgibt. Die Main-Methode veranschaulicht alle vier Methoden zum Aufrufen der Methode. Aufrufer müssen keine Argumente für Parameter angeben, die den params Modifizierer enthalten. In diesem Fall ist der Parameter eine leere Auflistung.
static class ParamsExample
{
static void Main()
{
string fromArray = GetVowels(["apple", "banana", "pear"]);
Console.WriteLine($"Vowels from collection expression: '{fromArray}'");
string fromMultipleArguments = GetVowels("apple", "banana", "pear");
Console.WriteLine($"Vowels from multiple arguments: '{fromMultipleArguments}'");
string fromNull = GetVowels(null);
Console.WriteLine($"Vowels from null: '{fromNull}'");
string fromNoValue = GetVowels();
Console.WriteLine($"Vowels from no value: '{fromNoValue}'");
}
static string GetVowels(params IEnumerable<string>? input)
{
if (input == null || !input.Any())
{
return string.Empty;
}
char[] vowels = ['A', 'E', 'I', 'O', 'U'];
return string.Concat(
input.SelectMany(
word => word.Where(letter => vowels.Contains(char.ToUpper(letter)))));
}
}
// The example displays the following output:
// Vowels from array: 'aeaaaea'
// Vowels from multiple arguments: 'aeaaaea'
// Vowels from null: ''
// Vowels from no value: ''
Anmerkung
Vor C# 13 kann der params Modifizierer nur mit einem eindimensionalen Array verwendet werden.
Rückgabewerte von Methoden
Methoden können einen Wert an den Aufrufer zurückgeben. Wenn der Rückgabetyp (der Typ, der vor dem Methodennamen aufgeführt ist) nicht voidist, kann die Methode den Wert mithilfe des schlüsselworts return zurückgeben. Eine Anweisung mit dem schlüsselwort return gefolgt von einer Variablen, Konstante oder einem Ausdruck, die dem Rückgabetyp entspricht, gibt diesen Wert an den Methodenaufrufer zurück. Methoden mit einem nichtoiden Rückgabetyp sind erforderlich, um das schlüsselwort return zum Zurückgeben eines Werts zu verwenden. Das schlüsselwort return beendet auch die Ausführung der Methode.
Wenn der Rückgabetyp voidist, ist eine Rückgabe-Anweisung ohne Wert weiterhin nützlich, um die Ausführung der Methode zu beenden. Ohne das schlüsselwort return wird die Methode nicht mehr ausgeführt, wenn sie das Ende des Codeblocks erreicht.
Diese beiden Methoden verwenden z. B. das schlüsselwort return, um ganze Zahlen zurückzugeben:
class SimpleMath
{
public int AddTwoNumbers(int number1, int number2) =>
number1 + number2;
public int SquareANumber(int number) =>
number * number;
}
In diesem Beispiel werden ausdrückende Member verwendet, um den Rückgabewert der Methoden zuzuweisen. Diese Syntax ist eine Kurzform für Methoden, die eine einzelne Anweisung (Ausdruck) verwenden, um den Rückgabewert zu berechnen.
Sie können ihre Methoden auch mit einem Anweisungstext und einer return-Anweisung definieren:
class SimpleMathExtnsion
{
public int DivideTwoNumbers(int number1, int number2)
{
return number1 / number2;
}
}
Um einen von einer Methode zurückgegebenen Wert zu verwenden, kann die aufrufende Methode den Methodenaufruf an einer beliebigen Stelle verwenden, an der ein Wert desselben Typs ausreicht. Sie können den Rückgabewert auch einer Variablen zuweisen. Die folgenden drei Codebeispiele erreichen beispielsweise dasselbe Ziel:
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);
result = obj2.DivideTwoNumbers(6,2);
// The result is 3.
Console.WriteLine(result);
Manchmal möchten Sie, dass die Methode mehr als einen einzelnen Wert zurückgibt. Sie verwenden Tupeltypen und Tupelliterale, um mehrere Werte zurückzugeben. Der Tupeltyp definiert die Datentypen der Tupelelemente. Tupelliterale stellen die tatsächlichen Werte des zurückgegebenen Tupels bereit. Im folgenden Beispiel definiert (string, string, string, int) den Tupeltyp, der von der GetPersonalInfo-Methode zurückgegeben wird. Der Ausdruck (per.FirstName, per.MiddleName, per.LastName, per.Age) ist das Tupelliteral; die Methode gibt den ersten, mittleren und familiennamen zusammen mit dem Alter eines PersonInfo-Objekts zurück.
public (string, string, string, int) GetPersonalInfo(string id)
{
PersonInfo per = PersonInfo.RetrieveInfoById(id);
return (per.FirstName, per.MiddleName, per.LastName, per.Age);
}
Der Aufrufer kann dann das zurückgegebene Tupel mithilfe des folgenden Codes verwenden:
var person = GetPersonalInfo("111111111");
Console.WriteLine($"{person.Item1} {person.Item3}: age = {person.Item4}");
Namen können auch den Tupelelementen in der Tupeltypdefinition 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);
return (per.FirstName, per.MiddleName, per.LastName, per.Age);
}
Der vorherige Aufruf der GetPersonalInfo-Methode kann dann wie folgt geändert werden:
var person = GetPersonalInfo("111111111");
Console.WriteLine($"{person.FName} {person.LName}: age = {person.Age}");
Wenn eine Methode ein Array als Parameter verwendet und den Wert einzelner Elemente ändert, ist es nicht erforderlich, dass die Methode das Array zurückgibt. C# übergibt alle Verweistypen nach Wert, und der Wert eines Arraybezugs ist der Zeiger auf das Array.
Ausdruckskörperliche Mitglieder
Es ist üblich, dass Methodendefinitionen vorhanden sind, die sofort mit dem Ergebnis eines Ausdrucks oder mit einer einzelnen Anweisung als Textkörper der Methode zurückgegeben werden. Es gibt eine Syntaxverknüpfung zum Definieren solcher Methoden mithilfe von =>:
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 eine asynchrone Methode ist, muss der Textkörper der Methode ein Anweisungsausdruck sein (identisch mit Lambdas). Für Eigenschaften und Indexer müssen sie schreibgeschützt sein, und Sie verwenden nicht das Schlüsselwort get Accessor.