TOC

This article is currently in the process of being translated into German (~48% done).

Klassen:

Method parameters

Im vorherigen Artikel haben wir bereits über Methoden gesprochen und eine kurze Einführung in das Konzept der Methoden- und Funktionsparameter erhalten. In diesem Artikel werden wir dieses Thema in all seinen Varianten vertiefen. Wie bereits erwähnt, können Methoden ohne Parameter funktionieren. Aber normalerweise haben sie einen oder mehrere Parameter, die der Methode bei der Erledigung ihrer Aufgabe helfen.

Im vorigen Artikel haben wir bereits ein sehr einfaches Beispiel für die Anwenung von Parametern gesehen: Unsere Methode AddNumbers(), die zwei Zahlen als Parameter übernimmt und die Summe dieser beiden Zahlen zurückgibt:

public int AddNumbers(int number1, int number2)
{
	return number1 + number2;
}

Dies zeigt, wie gut das Konzept der Methoden ist. Mit Methoden kann man die Funktionsweise in der Methode kapseln, aber das Ergebnis beim Aufruf dieser Methode durch Parameter beeinflussen:

AddNumbers(2, 3);

Result: 5

AddNumbers(38, 4);

Result: 42

Hier wurden lediglich Basistypen als Parameter verwendet. Aber lass uns einmal über die verschiedenen Modifikatoren und Optionen sprechen, mit denen wir das Verhalten der Parameter ändern können.

Bitte beachte, dass wir in diesem Artikel wirklich tief in die ganzen Parametertypen, und wie du sie am besten für dich verwendest, einsteigen. Wenn du gerade erst mit C# angefangen hast und lieber schnell ein paar Ergebnisse sehen möchtest, kann das durchaus etwas zu komplex sein. In diesem Fall kannst du den Artikel auch erst einmal überspringen und zu einem späteren Zeitpunkt zurückkehren.

Optionale Parameter

Wenn Sie eine Methode mit einem oder mehreren Parametern aufrufen, müssen Sie standardmäßig Werte für alle diese Parameter angeben. In einigen Situationen müssen Sie jedoch möglicherweise einen oder mehrere Parameter optional machen. In einigen Programmiersprachen ist dies möglich, indem Sie den Parameter einfach als optional markieren, aber in C# wird ein Parameter optional, indem ein Standardwert dafür in der Methodendeklaration bereitgestellt wird. Dies ist eigentlich eine nette Lösung, weil es Ihnen erspart, zusätzlichen Code zu schreiben, um mit Situationen fertig zu werden, in denen der Parameter nicht vom Aufrufer bereitgestellt wird.

Hier ist ein Beispiel einer Methode mit optionalem Parameter:

public int AddNumbers(int number1, int number2, int number3 = 0)
{
	return number1 + number2 + number3;
}

Der letzte Parameter (number 3) ist jetzt optional, da wir einen Standardwert für ihn haben. Jetzt kann man der Funktion 2 oder 3 Parameter übergeben:

public void Main(string[] args)
{
	AddNumbers(38, 4);
	AddNumbers(36, 4, 2);
}

Du kannst mehr als einen Parameter optional machen - deine Methode darf auch nur aus optionalen Parametern bestehen. Aber denk daran optionale Parameter müssen hinten in der Methoden-Deklaration stehen - nicht vorne oder zwischen nicht-optionalen Parametern.

Der params Modifikator

Eine Alternative für optionale Parameter ist der params Modifikator. Dieser erlaubt eine beliebig große Anzahl an Parametern. Das sieht wie folgt aus:

public void GreetPersons(params string[] names) { }

Die Methode aufzurufen könnte dann so aussehen:

GreetPersons("John", "Jane", "Tarzan");

Ein weiterer Vorteil der Verwendung des params-Ansatzes besteht darin, dass Sie der Methode auch keine Parameter übergeben können. Methoden mit params können auch normale Parameter annehmen, solange der Parameter mit dem params-Modifizierer der letzte ist. Außerdem kann pro Methode nur ein Parameter mit dem Schlüsselwort params verwendet werden. Hier ist ein vollständiges Beispiel, in dem wir den params-Modifizierer verwenden, um eine variable Anzahl von Namen mit unserer Methode GreetPersons() auszugeben:

public void Main(string[] args)
{
	GreetPersons("John", "Jane", "Tarzan");
}

public void GreetPersons(params string[] names)
{
	foreach(string name in names)
		Console.WriteLine("Hello " + name);
}

Parameter Typen: Wert oder Referenz

C# und auch andere Programmiersprachen unterscheiden zwischen zwei Parametertypen: "by value" und "by reference". Der Standardwert in C# ist "by value", was im Grunde bedeutet, dass Sie beim Übergeben einer Variablen an eine Methode tatsächlich eine Kopie des Objekts senden, anstatt einen Verweis darauf. Das bedeutet auch, dass Sie den Parameter innerhalb der Methode ändern können, ohne das ursprüngliche Objekt, das Sie als Parameter übergeben haben, zu beeinflussen.

Dieses Verhalten können wir an einem einfachen Beispiel demonstrieren:

public void Main(string[] args)
{
	int number = 20;
	AddFive(number);
	Console.WriteLine(number);
}

public void AddFive(int number)
{
	number = number + 5;
}

Wir haben eine sehr einfache Methode namens AddFive(), die 5 zu der Zahl hinzufügt, die wir ihr übergeben. Also erstellen wir in unserer Main()-Methode eine Variable namens number mit dem Wert 20 und rufen dann die AddFive()-Methode auf. Wenn wir nun in der nächsten Zeile den Variablenwert ausgeben, könnte man erwarten, dass der Wert jetzt 25 ist, aber stattdessen bleibt er 20. Warum? Da der Parameter standardmäßig als Kopie des ursprünglichen Objekts (nach Wert) übergeben wurde, wirkte unsere AddFive()-Methode also auf eine Kopie des Parameters und änderte daher nie die ursprüngliche Variable.

Im Moment gibt es 2 Wege, dieses Verhalten zu ändern, so dass es unserer AddFive()-Methode erlaubt ist, Original-Werte zu verändern: Wir können den ref-Modifizierer oder die in/out-Modifizierer verwenden.

Der ref Modifikator

The ref modifier is short for "reference" and it basically just changes the behavior of the parameter from the default behavior of "by value" to "by reference", meaning that we are now passing in a reference to the original variable instead of a copy of its value. Here's a modified example:

public void Main(string[] args)
{
	int number = 20;
	AddFive(ref number);
	Console.WriteLine(number);
}

public void AddFive(ref int number)
{
	number = number + 5;
}

You will notice that I have added the "ref" keyword in two places: In the method declaration and when passing in the parameter in the method call. With this change, we now get the behavior we originally might have expected - the result is now 25 instead of 20, because the ref modifier allows the method to work on the actual value passed in as a parameter instead of a copy.

Der out Modifikator

Genau wie der ref-Modifikator sorgt der out-Modifikator dafür, dass der Parameter als Referenz und nicht als Wert übergeben wird, aber es gibt einen großen Unterschied: Bei der Verwendung des ref-Modifizierers wird ein initialisierter Wert übergeben, den Sie innerhalb der Methode ändern oder unverändert lassen können. Bei der Verwendung des out-Modifikators hingegen sind Sie gezwungen, den Parameter innerhalb der Methode zu initialisieren. Das bedeutet auch, dass Sie bei Verwendung des out-Modifizierers nicht initialisierte Werte übergeben können - der Compiler wird sich beschweren, wenn Sie versuchen, eine Methode mit einem out-Parameter zu verlassen, ohne ihm einen Wert zuzuweisen.

In C#, a method can only return one value, but if you use the out modifier, you are able to circumvent this by passing in several parameters with the out modifier - when the method has been called, all out parameters will have been assigned. Here's an example, where we pass in two numbers and then, using out modifiers, return both an addition and a subtraction using these numbers:

public void Main(string[] args)
{
	int addedValue, subtractedValue;
	DoMath(10, 5, out addedValue, out subtractedValue);
	Console.WriteLine(addedValue);
	Console.WriteLine(subtractedValue);
}

public void DoMath(int number1, int number2, out int addedValue, out int subtractedValue)
{
	addedValue = number1 + number2;
	subtractedValue = number1 - number2;
}
Output:

15
5

As you can see in the beginning of the example, I declare the two variables (addedValue and subtractedValue) before passing them as out parameters. This was a requirement in previous versions of the C# language, but from C# version 6, you can declare them directly in the method call, like this:

DoMath(10, 5, out int addedValue, out int subtractedValue);
Console.WriteLine(addedValue);
Console.WriteLine(subtractedValue);

The in modifier

Just like the out modifier, the in modifier ensures that the parameter is passed as a reference instead of a copy of the value, but unlike the out modifier, the in modifier will prevent you from making any changes to the variable inside the method.

Your first thought might be: If I can't change the value of the parameter, then I might as well just pass it in as a regular parameter, where changes won't affect the original variable. And you're right, the result would appear to be exactly the same, but there's still a very valid reason for using the in modifier: By passing it as a reference instead of a value, you are saving resources because the framework doesn't have to spend time creating a copy of the object when passing it to the method like a regular parameter.

In most cases, this won't make much of a difference, because most parameters are simple strings or integers, but in situations where you repeatedly call the same method many times in a loop or where you pass in parameters with large values, e.g. very large strings or structs, this may give you a nice performance boost.

Here's an example where we use the in modifier:

public void Main(string[] args)
{
	string aVeryLargeString = "Lots of text...";
	InMethod(aVeryLargeString);
}

public void InMethod(in string largeString)
{
	Console.WriteLine(largeString);
}

In our method, InMethod(), the largeString parameter is now a read-only reference to the original variable (aVeryLargeString), so we're able to use it, but not modify it. If we try, the compiler will complain:

public void InMethod(in string largeString)
{
	largeString = "We can't do this...";
}

Error: Cannot assign to variable 'in string' because it is a readonly variable

Named parameters

As you have seen in all of the examples above, each parameter has a unique name in the method declaration. This allows you to reference the parameter inside the method. However, when calling the method, you don't use these names - you just supply the values in the same order as they are declared. This is not a problem for simple methods which takes 2-3 parameters, but some methods are more complex and requires more parameters. In those situations, it can be quite hard to figure out what the various values in a method call refers to, like in this example:

PrintUserDetails(1, "John", 42, null);

It's not very clear what the various parameters means in this method call, but if you look at the method declaration, you can see it:

public void PrintUserDetails(int userId, string name, int age = -1, List<string> addressLines = null)
{
	// Print details...
}

But it's annoying if you constantly have to look up the method declaration to understand what the parameters are doing, so for more complex methods, you can supply the parameter names directly in the method call. This also allows you to supply the parameter names in any order, instead of being forced to use the declaration order. Here's an example:

PrintUserDetails(name: "John Doe", userId: 1);

As an added bonus, this will allow you to supply a value for any of your optional parameters, without having to supply values for all previous optional parameters in the declaration. In other words, if you want to supply a value for the addressLines parameter in this example you would also have to provide a value for the age parameter, because it comes first in the method declaration. However, if you use named parameters, order no longer matters and you can just supply values for the required parameters as well as one or several of the optional parameters, e.g. like this:

PrintUserDetails(addressLines: new List<string>() { }, name: "Jane Doe", userId: 2);

Here's the complete example of using named parameters:

public void Main(string[] args)
{
	PrintUserDetails(1, "John", 42, null);
	PrintUserDetails(name: "John Doe", userId: 1);
	PrintUserDetails(addressLines: new List<string>() { }, name: "Jane Doe", userId: 2);
}

public void PrintUserDetails(int userId, string name, int age = -1, List<string> addressLines = null)
{
	// Print details...
	Console.WriteLine(name + " is " + age + " years old...");
}

Zusammenfassung

As you can see from this article, parameters come in many forms and types. Fortunately, you'll come along way with plain, old regular parameters, but once you start to dig deeper into the C# language, you will benefit from knowing all the types and modifiers as explained in this article.


This article has been fully translated into the following languages: Is your preferred language not on the list? Click here to help us translate this article into your language!