Uwaga
Dostęp do tej strony wymaga autoryzacji. Może spróbować zalogować się lub zmienić katalogi.
Dostęp do tej strony wymaga autoryzacji. Możesz spróbować zmienić katalogi.
Metoda to blok kodu, który zawiera serię instrukcji. Program powoduje wykonanie instrukcji przez wywołanie metody i określenie wszelkich wymaganych argumentów metody. W języku C# każda wykonywana instrukcja jest wykonywana w kontekście metody.
Uwaga
W tym artykule omówiono metody nazwane. Aby uzyskać informacje o funkcjach anonimowych, zobacz Wyrażenia lambda.
Podpisy metod
Metody są deklarowane w obiekcie class
, record
lub struct
przez określenie:
- Opcjonalny poziom dostępu, taki jak
public
lubprivate
. Wartość domyślna toprivate
. - Opcjonalne modyfikatory, takie jak
abstract
lubsealed
. - Wartość zwracana lub
void
jeśli metoda nie zwraca żadnej wartości. - Nazwa metody.
- Wszystkie parametry metody. Parametry metody są ujęte w nawiasy i są oddzielone przecinkami. Puste nawiasy wskazują, że metoda nie wymaga żadnych parametrów.
Te części razem tworzą sygnaturę metody.
Ważne
Zwracany typ metody nie jest częścią podpisu metody na potrzeby przeciążenia metody. Jednak jest to część podpisu metody podczas określania zgodności między delegatem a metodą, do której wskazuje.
W poniższym przykładzie zdefiniowano klasę o nazwie Motorcycle
zawierającą pięć metod:
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();
}
Klasa Motorcycle
zawiera przeciążoną metodę Drive
. Dwie metody mają taką samą nazwę, ale ich listy parametrów je rozróżniają.
Wywołanie metody
Metody mogą być instancyjnymi lub statycznymi. Należy utworzyć instancję obiektu, aby wywołać metodę instancji na tej instancji; metoda instancji działa na tej instancji i jej danych. Metoda statyczna jest wywoływana przez odwoływanie się do nazwy typu, do którego należy metoda; metody statyczne nie działają na danych wystąpienia. Próba wywołania metody statycznej za pomocą wystąpienia obiektu generuje błąd kompilatora.
Wywoływanie metody przypomina uzyskiwanie dostępu do pola. Po nazwie obiektu (jeśli wywołujesz metodę wystąpienia) lub nazwie typu (jeśli wywołujesz metodę static
), dodaj kropkę, nazwę metody i nawiasy. Argumenty są wymienione w nawiasach i są rozdzielane przecinkami.
Definicja metody określa nazwy i typy wszystkich wymaganych parametrów. Gdy obiekt wywołujący wywołuje metodę, udostępnia konkretne wartości, nazywane argumentami, dla każdego parametru. Argumenty muszą być zgodne z typem parametru, ale nazwa argumentu, jeśli jest używana w kodzie wywołującym, nie musi być taka sama jak parametr o nazwie zdefiniowanej w metodzie. W poniższym przykładzie Square
metoda zawiera jeden parametr typu int
o nazwie i. Pierwsze wywołanie metody przekazuje do metody Square
zmienną typu int
o nazwie num; drugie wywołanie - stałą liczbową, a trzecie wywołanie - wyrażenie.
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;
}
}
Najbardziej typowa forma wywołania metody używa argumentów pozycyjnych; dostarcza argumenty w tej samej kolejności co parametry metody. Metody Motorcycle
klasy można zatem wywołać tak, jak w poniższym przykładzie. Wywołanie Drive
metody, na przykład, zawiera dwa argumenty, które odpowiadają dwóm parametrom w składni metody. Pierwszy staje się wartością parametru miles
. Drugi staje się wartością parametru speed
.
class TestMotorcycle : Motorcycle
{
public override double GetTopSpeed() => 108.4;
static void Main()
{
var moto = new TestMotorcycle();
moto.StartEngine();
moto.AddGas(15);
_ = moto.Drive(5, 20);
double speed = moto.GetTopSpeed();
Console.WriteLine($"My top speed is {speed}");
}
}
Podczas wywoływania metody można również użyć nazwanych argumentów zamiast argumentów pozycyjnych. W przypadku używania nazwanych argumentów należy określić nazwę parametru, po którym następuje dwukropek (":") i argument. Argumenty metody mogą być wyświetlane w dowolnej kolejności, o ile wszystkie wymagane argumenty są obecne. W poniższym przykładzie użyto nazwanych argumentów do wywołania TestMotorcycle.Drive
metody . W tym przykładzie nazwane argumenty są przekazywane w odwrotnej kolejności z listy parametrów metody.
namespace NamedMotorCycle;
class TestMotorcycle : Motorcycle
{
public override int Drive(int miles, int speed) =>
(int)Math.Round((double)miles / speed, 0);
public override double GetTopSpeed() => 108.4;
static void Main()
{
var moto = new TestMotorcycle();
moto.StartEngine();
moto.AddGas(15);
int travelTime = moto.Drive(speed: 60, miles: 170);
Console.WriteLine($"Travel time: approx. {travelTime} hours");
}
}
// The example displays the following output:
// Travel time: approx. 3 hours
Metodę można wywołać przy użyciu argumentów pozycyjnych i argumentów nazwanych. Jednak argumenty pozycyjne mogą występować tylko po nazwanych argumentach, gdy nazwane argumenty znajdują się na poprawnych pozycjach. Poniższy przykład wywołuje metodę TestMotorcycle.Drive
z poprzedniego przykładu przy użyciu jednego argumentu pozycyjnego i jednego nazwanego argumentu.
int travelTime = moto.Drive(170, speed: 55);
Metody dziedziczone i nadpisane
Oprócz elementów, które są jawnie zdefiniowane w typie, typ dziedziczy elementy zdefiniowane w klasach bazowych. Ponieważ wszystkie typy w zarządzanym systemie typów dziedziczą bezpośrednio lub pośrednio z Object klasy, wszystkie typy dziedziczą jego składowe, takie jak Equals(Object), GetType()i ToString(). W poniższym przykładzie zdefiniowano klasę Person
, utworzono dwa obiekty Person
i wywołano metodę Person.Equals
w celu określenia, czy te dwa obiekty są równe. Metoda Equals
nie jest jednak zdefiniowana w Person
klasie ; jest dziedziczona z Objectklasy .
public class Person
{
public string FirstName = default!;
}
public static class ClassTypeExample
{
public static void Main()
{
Person p1 = new() { FirstName = "John" };
Person p2 = new() { FirstName = "John" };
Console.WriteLine($"p1 = p2: {p1.Equals(p2)}");
}
}
// The example displays the following output:
// p1 = p2: False
Typy mogą zastępować dziedziczone elementy członkowskie, używając słowa kluczowego override
i dostarczając implementację dla metody przesłoniętej. Sygnatura metody musi być taka sama jak przesłanianej metody. Poniższy przykład jest podobny do poprzedniego, z tą różnicą, że zastępuje metodę Equals(Object) . (Zastępuje również metodę GetHashCode() , ponieważ obie metody mają na celu zapewnienie spójnych wyników).
namespace methods;
public class Person
{
public string FirstName = default!;
public override bool Equals(object? obj) =>
obj is Person p2 &&
FirstName.Equals(p2.FirstName);
public override int GetHashCode() => FirstName.GetHashCode();
}
public static class Example
{
public static void Main()
{
Person p1 = new() { FirstName = "John" };
Person p2 = new() { FirstName = "John" };
Console.WriteLine($"p1 = p2: {p1.Equals(p2)}");
}
}
// The example displays the following output:
// p1 = p2: True
Przekazywanie parametrów
Typy w języku C# to typy wartości lub typy referencyjne. Aby uzyskać listę wbudowanych typów wartości, zobacz Typy. Domyślnie zarówno typy wartości, jak i typy referencyjne są przekazywane przez wartość do metody.
Przekazywanie parametrów według wartości
Gdy typ wartości jest przekazywany do metody przez wartość, do metody przekazywana jest kopia obiektu, zamiast samego obiektu. W związku z tym zmiany obiektu w wywoływanej metodzie nie mają wpływu na oryginalny obiekt, gdy kontrolka powraca do obiektu wywołującego.
Poniższy przykład przekazuje typ wartości do metody według wartości, a wywołana metoda próbuje zmienić wartość typu wartości. Definiuje zmienną typu int
, która jest typem wartości, inicjuje jej wartość do 20 i przekazuje ją do metody o nazwie ModifyValue
, która zmienia wartość zmiennej na 30. Gdy jednak metoda zwróci wartość zmiennej, pozostaje niezmieniona.
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
Gdy obiekt typu referencyjnego jest przekazywany do metody przez wartość, przekazywana jest referencja do obiektu przez wartość. Oznacza to, że metoda nie odbiera samego obiektu, ale argument wskazujący lokalizację obiektu. Jeśli zmienisz element członkowski obiektu przy użyciu tego odwołania, zmiana zostanie odzwierciedlona w obiekcie, gdy kontrolka powróci do metody wywołującej. Jednak zastąpienie obiektu przekazanego do metody nie ma wpływu na oryginalny obiekt, gdy kontrolka powróci do obiektu wywołującego.
W poniższym przykładzie zdefiniowano klasę (która jest typem odwołania) o nazwie SampleRefType
. Tworzy wystąpienie obiektu SampleRefType
, przypisuje 44 do jego pola value
i przekazuje obiekt do metody ModifyObject
. W tym przykładzie zasadniczo dzieje się to samo, co w poprzednim przykładzie — argument jest przekazywany do metody według wartości. Ale ponieważ jest używany typ odwołania, wynik jest inny. Modyfikacja wprowadzona w ModifyObject
do obj.value
pola również zmienia value
pole argumentu, rt
, w metodzie Main
na 33, co pokazuje wynik z przykładu.
public class SampleRefType
{
public int value;
}
public static class ByRefTypeExample
{
public static void Main()
{
var rt = new SampleRefType { value = 44 };
ModifyObject(rt);
Console.WriteLine(rt.value);
}
static void ModifyObject(SampleRefType obj) => obj.value = 33;
}
Przekazywanie parametrów przez referencję
Parametr jest przekazywany przez odwołanie, gdy chcesz zmienić wartość argumentu w metodzie i chcesz odzwierciedlić tę zmianę, gdy kontrolka powróci do metody wywołującej. Aby przekazać parametr za pomocą odwołania, należy użyć słowa kluczowego ref
lub out
. Możesz również przekazać wartość przy użyciu odwołania, aby uniknąć kopiowania, ale nadal zapobiegać modyfikacjom przy użyciu słowa kluczowego in
.
Poniższy przykład jest identyczny z poprzednim, z tą różnicą, że wartość jest przekazywana przez odwołanie do ModifyValue
metody . Gdy wartość parametru zostanie zmodyfikowana w metodzie ModifyValue
, zmiana wartości zostanie odzwierciedlona, gdy kontrolka powróci do obiektu wywołującego.
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
Typowy wzorzec używany przez parametry ref obejmuje zamianę wartości zmiennych. Przekazujesz dwie zmienne do metody przez referencję, a metoda zamienia ich zawartość. Poniższy przykład zamienia wartości całkowite.
public static class RefSwapExample
{
static void Main()
{
int i = 2, j = 3;
Console.WriteLine($"i = {i} j = {j}");
Swap(ref i, ref j);
Console.WriteLine($"i = {i} j = {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
Przekazanie parametru typu odwołania umożliwia zmianę wartości samego odwołania, a nie wartości poszczególnych elementów lub pól.
Kolekcje parametrów
Czasami wymaganie, aby określić dokładną liczbę argumentów dla metody, jest restrykcyjne. Używając słowa kluczowego wskazującego params
, że parametr jest kolekcją parametrów, można wywołać metodę przy użyciu zmiennej liczby argumentów. Parametr oznaczony params
słowem kluczowym musi być typem kolekcji i musi być ostatnim parametrem na liście parametrów metody.
Obiekt wywołujący może następnie wywołać metodę na jeden z czterech sposobów dla parametru params
:
- Przekazując kolekcję odpowiedniego typu, która zawiera żądaną liczbę elementów. W przykładzie użyto wyrażenia kolekcji, aby kompilator stworzył odpowiedni typ kolekcji.
- Przekazując rozdzielaną przecinkami listę poszczególnych argumentów odpowiedniego typu do metody. Kompilator tworzy odpowiedni typ kolekcji.
- Przekazując wartość
null
. - Nie podając argumentu do kolekcji parametrów.
W poniższym przykładzie zdefiniowano metodę o nazwie GetVowels
, która zwraca wszystkie vowels z kolekcji parametrów. Metoda Main
ilustruje wszystkie cztery sposoby wywoływania metody. Obiekty wywołujące nie muszą dostarczać żadnych argumentów dla parametrów, które zawierają modyfikator params
. W takim przypadku parametr jest pustą kolekcją.
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: ''
Przed C# 13 modyfikator params
może być używany tylko z jednowymiarową tablicą.
Opcjonalne parametry i argumenty
Definicja metody może określić, że jego parametry są wymagane lub że są opcjonalne. Domyślnie wymagane są parametry. Parametry opcjonalne są określane przez uwzględnienie wartości domyślnej parametru w definicji metody. Gdy metoda jest wywoływana, jeśli dla opcjonalnego parametru nie zostanie podany żaden argument, zamiast tego zostanie użyta wartość domyślna.
Wartość domyślna parametru jest przypisywana z jednym z następujących rodzajów wyrażeń:
Stała, taka jak napis lub liczba.
Wyrażenie formularza
default(SomeType)
, w którymSomeType
może być typem wartości lub typem odwołania. Jeśli jest to typ odwołania, jest to w zasadzie to samo, co określenienull
. Możesz użyć literałudefault
, ponieważ kompilator może wywnioskować typ z deklaracji parametru.Wyrażenie formularza
new ValType()
, gdzieValType
jest typem wartości. To wyrażenie wywołuje niejawny konstruktor bezparametrowy typu wartościowego, który nie jest rzeczywistym członkiem tego typu.Uwaga
Gdy wyrażenie formularza
new ValType()
wywołuje jawnie zdefiniowany konstruktor bez parametrów typu wartości, kompilator generuje błąd, ponieważ domyślna wartość parametru musi być stałą czasu kompilacji. Użyj wyrażeniadefault(ValType)
lub literałudefault
, aby podać domyślną wartość parametru. Aby uzyskać więcej informacji na temat konstruktorów bez parametrów, zobacz sekcję Inicjowanie struktury i wartości domyślne w artykule Typy struktury.
Jeśli metoda zawiera zarówno wymagane, jak i opcjonalne parametry, parametry opcjonalne są definiowane na końcu listy parametrów, po wszystkich wymaganych parametrach.
W poniższym przykładzie zdefiniowano metodę , ExampleMethod
która ma jeden wymagany i dwa parametry opcjonalne.
public class Options
{
public void ExampleMethod(int required, int optionalInt = default,
string? description = default)
{
var msg = $"{description ?? "N/A"}: {required} + {optionalInt} = {required + optionalInt}";
Console.WriteLine(msg);
}
}
Obiekt wywołujący musi podać argument dla wszystkich parametrów opcjonalnych do ostatniego opcjonalnego parametru, dla którego podano argument. W metodzie ExampleMethod
, na przykład jeśli obiekt wywołujący dostarcza argument dla parametru description
, musi również podać jeden dla parametru optionalInt
.
opt.ExampleMethod(2, 2, "Addition of 2 and 2");
jest prawidłowym wywołaniem metody; opt.ExampleMethod(2, , "Addition of 2 and 0");
Generuje błąd kompilatora "Brak argumentu".
Jeśli metoda jest wywoływana przy użyciu nazwanych argumentów lub kombinacji argumentów pozycyjnych i nazwanych, obiekt wywołujący może pominąć wszelkie argumenty, które są zgodne z ostatnim argumentem pozycyjnym w wywołaniu metody.
Poniższy przykład wywołuje metodę ExampleMethod
trzy razy. Pierwsze dwie metody używają argumentów pozycyjnych. Pierwszy pomija oba opcjonalne argumenty, podczas gdy drugi pomija ostatni argument. Trzecie wywołanie metody dostarcza argument pozycyjny dla wymaganego parametru, ale używa nazwanego argumentu, aby podać wartość parametrowi description
podczas pomijania argumentu optionalInt
.
public static class OptionsExample
{
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:
// N/A: 10 + 0 = 10
// N/A: 10 + 2 = 12
// Addition with zero:: 12 + 0 = 12
Użycie parametrów opcjonalnych wpływa na rozpoznawanie przeciążeń lub sposób, w jaki kompilator języka C# określa, które przeciążenie ma być wywoływane dla wywołania metody w następujący sposób:
- Element członkowski jest kandydatem do wykonania, jeśli każdy z jego parametrów odpowiada nazwie lub pozycji do jednego argumentu. Ponadto ten argument można przekonwertować na typ parametru.
- Jeśli zostanie znalezionych więcej niż jeden kandydat, reguły rozpoznawania przeciążenia dla preferowanych konwersji zostaną zastosowane do tych argumentów, które są jawnie określone. Pominięte argumenty parametrów opcjonalnych są ignorowane.
- Jeśli dwaj kandydaci są oceniani jako równie dobrzy, preferencja trafia do kandydata, który nie ma opcjonalnych parametrów, dla których argumenty zostały pominięte w wywołaniu.
Wartości zwracane
Metody mogą zwracać wartość wywołującemu. Jeśli zwracany typ (typ wymieniony przed nazwą metody) nie jest void
, metoda może zwrócić wartość, używając słowa kluczowego return
. Instrukcja zawierająca return
słowo kluczowe, po którym następuje zmienna, stała lub wyrażenie zgodne z typem zwracanym, zwraca tę wartość do wywołującego metodę. Metody z typem zwrotnym innym niż void wymagają użycia słowa kluczowego return
w celu zwrócenia wartości. Słowo return
kluczowe zatrzymuje również wykonywanie metody .
Jeśli zwracany typ to void
, instrukcja return
bez wartości jest nadal przydatna do zatrzymania wykonywania metody. Bez słowa kluczowego return
metoda zatrzymuje wykonywanie, gdy osiągnie koniec bloku kodu.
Na przykład te dwie metody używają słowa kluczowego return
do zwracania liczb całkowitych:
class SimpleMath
{
public int AddTwoNumbers(int number1, int number2) =>
number1 + number2;
public int SquareANumber(int number) =>
number * number;
}
Powyższe przykłady to składowe wyrażeń. Elementy członkowskie wyrażeń zwracają wartość zwracaną przez wyrażenie.
Możesz również zdefiniować metody za pomocą treści instrukcji i instrukcji return
:
class SimpleMathExtension
{
public int DivideTwoNumbers(int number1, int number2)
{
return number1 / number2;
}
}
Aby użyć wartości zwróconej z metody, możesz przypisać wartość zwracaną do zmiennej:
int result = obj.DivideTwoNumbers(6,2);
// The result is 3.
Console.WriteLine(result);
Metoda wywołująca może również używać wywołania metody w dowolnym miejscu, gdzie wartość tego samego typu byłaby wystarczająca. Na przykład następujące dwa przykłady kodu osiągają ten sam cel:
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);
Czasami chcesz, aby metoda zwróciła więcej niż jedną wartość. Aby zwrócić wiele wartości, należy użyć typów krotek i literałów krotek. Typ krotki definiuje typy danych elementów krotki. Literały krotki zapewniają rzeczywiste wartości zwracanej krotki. W poniższym przykładzie (string, string, string, int)
definiuje typ krotki zwracany przez metodę GetPersonalInfo
. Wyrażenie (per.FirstName, per.MiddleName, per.LastName, per.Age)
jest literałem krotki; metoda zwraca imię, drugie imię, nazwisko oraz wiek obiektu PersonInfo
.
public (string, string, string, int) GetPersonalInfo(string id)
{
PersonInfo per = PersonInfo.RetrieveInfoById(id);
return (per.FirstName, per.MiddleName, per.LastName, per.Age);
}
Obiekt wywołujący może następnie korzystać z zwróconej krotki przy użyciu następującego kodu:
var person = GetPersonalInfo("111111111");
Console.WriteLine($"{person.Item1} {person.Item3}: age = {person.Item4}");
Nazwy można również przypisać elementom krotki w definicji typu krotki. W poniższym przykładzie przedstawiono alternatywną wersję GetPersonalInfo
metody, która używa nazwanych elementów:
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);
}
Poprzednie wywołanie GetPersonalInfo
metody można następnie zmodyfikować w następujący sposób:
var person = GetPersonalInfo("111111111");
Console.WriteLine($"{person.FName} {person.LName}: age = {person.Age}");
Jeśli metoda przyjmuje tablicę jako parametr i modyfikuje wartość poszczególnych elementów, nie jest konieczne, aby metoda zwróciła tablicę. Język C# przekazuje wszystkie typy odwołań według wartości, a wartość odwołania do tablicy jest wskaźnikiem do tablicy. W poniższym przykładzie zmiany zawartości values
tablicy wprowadzonej w DoubleValues
metodzie można zaobserwować za pomocą dowolnego kodu, który zawiera odwołanie do tablicy.
public static class ArrayValueExample
{
static void Main()
{
int[] values = [2, 4, 6, 8];
DoubleValues(values);
foreach (var value in values)
{
Console.Write("{0} ", value);
}
}
public static void DoubleValues(int[] arr)
{
for (var ctr = 0; ctr <= arr.GetUpperBound(0); ctr++)
{
arr[ctr] *= 2;
}
}
}
// The example displays the following output:
// 4 8 12 16
Metody rozszerzeń
Zazwyczaj istnieją dwa sposoby dodawania metody do istniejącego typu:
- Zmodyfikuj kod źródłowy dla tego typu. Modyfikowanie źródła powoduje zmianę łamiącą kompatybilność, jeśli dodasz również jakiekolwiek prywatne pola danych w celu wsparcia działania metody.
- Zdefiniuj nową metodę w klasie pochodnej. Nie można w ten sposób dodać metody poprzez dziedziczenie do innych typów, takich jak struktury i wyliczenia. Nie można także użyć tego do "dodawania" metody do zamkniętej klasy.
Elementy członkowskie rozszerzenia umożliwiają dodawanie elementów członkowskich do istniejącego typu bez modyfikowania samego typu lub implementowania nowej metody w dziedziczony typ. Element członkowski rozszerzenia nie musi również znajdować się w tym samym zestawie, co typ, który rozszerza. Wywołujesz metodę rozszerzenia, tak jakby była zdefiniowaną składową typu.
Aby uzyskać więcej informacji, zobacz Elementy członkowskie rozszerzenia.
Metody asynchroniczne
Za pomocą funkcji asynchronicznej można wywoływać metody asynchroniczne bez użycia jawnych wywołań zwrotnych lub ręcznego dzielenia kodu między wiele metod lub wyrażeń lambda.
Jeśli oznaczysz metodę za pomocą modyfikatora asynchronicznego , możesz użyć operatora await w metodzie . Gdy sterowanie osiągnie wyrażenie await
w metodzie asynchronicznej, wraca ono do wywołującego, jeśli oczekiwane zadanie nie zostanie ukończone. Wówczas postęp w metodzie ze słowem kluczowym await
zostaje zawieszony do momentu zakończenia oczekiwanego zadania. W metodzie po zakończeniu zadania wykonanie może być wznowione.
Uwaga
Metoda asynchroniczna powraca do obiektu wywołującego, gdy napotka pierwszy oczekiwany obiekt, który nie został jeszcze ukończony, lub dotrze do końca metody asynchronicznej, w zależności od tego, co nastąpi wcześniej.
Metoda asynchroniczna zwykle ma zwracany typ Task<TResult>, Task, IAsyncEnumerable<T> lub void
. Typ zwracany void
jest używany głównie do definiowania procedur obsługi zdarzeń, gdzie wymagany jest void
. Nie można czekać na metodę asynchroniczną, która zwraca void
, a wywołujący metody zwracającej void nie może przechwycić wyjątków rzucanych przez tę metodę. Metoda asynchroniczna może mieć dowolny typ zwracania podobny do zadania.
W poniższym przykładzie DelayAsync
jest to metoda asynchronizna, która zawiera instrukcję return zwracającą liczbę całkowitą. Ponieważ jest to metoda asynchronizna, jego deklaracja metody musi mieć typ zwracany Task<int>
. Ponieważ zwracany typ to Task<int>
, wyrażenie await
w kontekście DoSomethingAsync
ocenia się do liczby całkowitej, jak pokazano w poniższej int result = await delayTask
instrukcji.
class Program
{
static Task Main() => DoSomethingAsync();
static async Task DoSomethingAsync()
{
Task<int> delayTask = DelayAsync();
int result = await delayTask;
// The previous two statements may be combined into
// the following statement.
//int result = await DelayAsync();
Console.WriteLine($"Result: {result}");
}
static async Task<int> DelayAsync()
{
await Task.Delay(100);
return 5;
}
}
// Example output:
// Result: 5
Metoda asynchroniczna nie może zadeklarować żadnych parametrów in, ref ani out, ale może wywoływać metody, które mają takie parametry.
Aby uzyskać więcej informacji na temat metod asynchronicznych, zobacz Programowanie asynchroniczne z async i await oraz Typy zwracane async.
Członkowie z ciałem wyrażeniowym
Często zdarza się, że definicje metod zwracają się natychmiast z wynikiem wyrażenia lub mają pojedynczą instrukcję jako treść metody. Istnieje skrót składniowy do definiowania takich metod przy użyciu metody =>
:
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);
Jeśli metoda zwraca void
lub jest metodą asynchroniczną, jej treść musi stanowić wyrażenie instrukcji (tak samo jak w przypadku lambd). W przypadku właściwości i indeksatorów, muszą być one ustawione jako tylko do odczytu i nie należy używać słowa kluczowego akcesora get
.
Iteratory
Iterator wykonuje niestandardowe iterowanie w kolekcji, jak lista lub tablica. Iterator używa instrukcji yield return, aby zwrócić każdy element jeden po drugim. Po osiągnięciu instrukcji yield return
, miejsce bieżące jest zapamiętane, aby obiekt wywołujący mógł zażądać następnego elementu w sekwencji.
Zwracany typ iteratora może być IEnumerable, IEnumerable<T>, IAsyncEnumerable<T>, IEnumerator lub IEnumerator<T>.
Aby uzyskać więcej informacji, zobacz Iteratory.