Metody w języku C#

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. Metoda Main jest punktem wejścia dla każdej aplikacji języka C# i jest wywoływana przez środowisko uruchomieniowe języka wspólnego (CLR) po uruchomieniu programu.

Uwaga

W tym temacie omówiono metody nazwane. Aby uzyskać informacje o funkcjach anonimowych, zobacz Wyrażenia lambda.

Podpisy metod

Metody są deklarowane w obiekcie class, recordlub struct przez określenie:

  • Opcjonalny poziom dostępu, taki jak public lub private. Wartość domyślna to private.
  • Opcjonalne modyfikatory, takie jak abstract lub sealed.
  • Wartość zwracana lub void jeśli metoda nie ma żadnej.
  • 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 do celów przeciążenia metody. Jednak jest ona częścią 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ążony metodę . Drive Dwie metody mają taką samą nazwę, ale muszą być rozróżniane przez ich typy parametrów.

Wywołanie metody

Metody mogą być wystąpieniem lub statycznym. Wywołanie metody wystąpienia wymaga utworzenia wystąpienia obiektu i wywołania metody w tym obiekcie; metoda wystąpienia działa na tym wystąpieniu i jego 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 metodę Square zmienną typu int o nazwie num; drugą, stałą liczbową, a trzecią wyrażeniem.

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 , drugą 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 {0}", 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(miles: 170, speed: 60);
        Console.WriteLine("Travel time: approx. {0} hours", travelTime);
    }
}
// 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ą być zgodne tylko z nazwanych argumentów, gdy nazwane argumenty znajdują się we 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 zastępowane

Oprócz składowych, które są jawnie zdefiniowane w typie, typ dziedziczy elementy członkowskie 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ę , tworzy Person wystąpienia dwóch Person obiektów i wywołuje metodę Person.Equals w celu określenia, czy 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: {0}", p1.Equals(p2));
    }
}
// The example displays the following output:
//      p1 = p2: False

Typy mogą zastępować dziedziczone elementy członkowskie przy użyciu słowa kluczowego override i dostarczać implementację dla metody przesłoniętej. Sygnatura metody musi być taka sama jak w przypadku metody przesłoniętej. 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: {0}", 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 do metody według wartości.

Przekazywanie parametrów według wartości

Gdy typ wartości jest przekazywany do metody według wartości, kopia obiektu zamiast samego obiektu jest przekazywana do metody . 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 odwołania jest przekazywany do metody według wartości, odwołanie do obiektu jest przekazywane 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 SampleRefType obiektu, przypisuje 44 do pola value i przekazuje obiekt do ModifyObject metody . W tym przykładzie zasadniczo jest to samo, co w poprzednim przykładzie — przekazuje argument według wartości do metody. Ale ponieważ jest używany typ odwołania, wynik jest inny. Modyfikacja wprowadzona w ModifyObjectobj.value polu zmienia value również pole argumentu , rtw Main metodzie na 33, jak pokazano w danych wyjściowych 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 według odwołania

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 według odwołania, 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 = {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

Przekazanie parametru typu odwołania umożliwia zmianę wartości samego odwołania, a nie wartości poszczególnych elementów lub pól.

Tablice 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 tablicą parametrów, można wywołać metodę ze zmienną liczbą argumentów. Parametr oznaczony params słowem kluczowym musi być typem tablicy 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:

  • Przekazując tablicę odpowiedniego typu zawierającego żądaną liczbę elementów.
  • Przekazując rozdzielaną przecinkami listę poszczególnych argumentów odpowiedniego typu do metody.
  • Przekazując wartość null.
  • Nie podając argumentu do tablicy parametrów.

W poniższym przykładzie zdefiniowano metodę o nazwie GetVowels , która zwraca wszystkie vowels z tablicy parametrów. Metoda Main ilustruje wszystkie cztery sposoby wywoływania metody. Obiekty wywołujące nie są wymagane do podania żadnych argumentów dla parametrów, które zawierają params modyfikator. W takim przypadku parametr jest pustą tablicą.

static class ParamsExample
{
    static void Main()
    {
        string fromArray = GetVowels(["apple", "banana", "pear"]);
        Console.WriteLine($"Vowels from array: '{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 string[]? input)
    {
        if (input == null || input.Length == 0)
        {
            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: ''

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 musi być przypisana przez jeden z następujących rodzajów wyrażeń:

  • Stała, taka jak ciąg literału lub liczba.

  • Wyrażenie formularza default(SomeType), w którym SomeType może być typem wartości lub typem odwołania. Jeśli jest to typ odwołania, jest on w rzeczywistości taki sam jak określenie nullelementu . Można użyć default literału, ponieważ kompilator może wywnioskować typ z deklaracji parametru.

  • Wyrażenie formularza new ValType(), gdzie ValType jest typem wartości. Spowoduje to wywołanie niejawnego konstruktora bez parametrów typu wartości, który nie jest rzeczywistym elementem członkowskim typu.

    Uwaga

    W języku C# 10 lub nowszym, 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. default(ValType) Użyj wyrażenia lub literału, aby podać domyślną wartość parametrudefault. 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ę , ExampleMethodktó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);
    }
}

Jeśli metoda z wieloma opcjonalnymi argumentami jest wywoływana przy użyciu argumentów pozycyjnych, obiekt wywołujący musi podać argument dla wszystkich parametrów opcjonalnych od pierwszego do ostatniego, dla którego podano argument. Na przykład w przypadku ExampleMethod metody , 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 powinno być wywoływane przez wywołanie metody w następujący sposób:

  • Metoda, indeksator lub konstruktor jest kandydatem do wykonania, jeśli każdy z jego parametrów jest opcjonalny lub odpowiada, według nazwy lub pozycji, do pojedynczego argumentu w instrukcji wywołującej i 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 są stosowane do 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. Jest to konsekwencja ogólnej preferencji w rozpoznawaniu przeciążenia dla kandydatów, którzy mają mniej parametrów.

Wartości zwracane

Metody mogą zwracać wartość do elementu wywołującego. Jeśli zwracany typ (typ wymieniony przed nazwą metody) nie voidjest , metoda może zwrócić wartość przy użyciu słowa kluczowego return . Instrukcja ze słowem kluczowym, po którym następuje zmienna, stała lub wyrażenie zgodne z return typem zwracanym, zwróci tę wartość do wywołującego metodę. Metody z typem zwracanym bez wartości są wymagane do użycia return słowa kluczowego w celu zwrócenia wartości. Słowo return kluczowe zatrzymuje również wykonywanie metody .

Jeśli zwracany typ to void, return instrukcja bez wartości jest nadal przydatna do zatrzymania wykonywania metody. Bez słowa kluczowego return metoda przestanie działać, 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;
}

Aby użyć wartości zwróconej z metody, metoda wywołująca może użyć wywołania metody w dowolnym miejscu, w jakim wartość tego samego typu byłaby wystarczająca. Możesz również przypisać wartość zwracaną do zmiennej. 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);

Użycie zmiennej lokalnej, w tym przypadku , resultdo przechowywania wartości jest opcjonalne. Może to pomóc w czytelności kodu lub może być konieczne, jeśli trzeba przechowywać oryginalną wartość argumentu dla całego zakresu metody.

Czasami chcesz, aby metoda zwróciła więcej niż jedną wartość. Można to łatwo zrobić przy użyciu typów krotki i literałów krotki. 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) zdefiniowano typ krotki zwracany przez metodę GetPersonalInfo . Wyrażenie (per.FirstName, per.MiddleName, per.LastName, per.Age) jest literałem krotki; metoda zwraca pierwszą, środkową i nazwisko wraz z wiekiem PersonInfo obiektu.

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 z kodem, tak jak poniżej:

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

Nazwy można również przypisać do elementów 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 jest przekazywana tablicy jako argument i modyfikuje wartość poszczególnych elementów, nie jest konieczne, aby metoda zwracała tablicę, chociaż można to zrobić dla dobrego stylu lub przepływu funkcjonalnego wartości. Dzieje się tak, ponieważ 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 tego typu. Nie można tego zrobić, oczywiście, jeśli nie jesteś właścicielem kodu źródłowego typu. A to staje się zmianą powodującą niezgodność, jeśli dodasz również dowolne pola danych prywatnych do obsługi metody .
  • Zdefiniuj nową metodę w klasie pochodnej. Nie można dodać metody w ten sposób przy użyciu dziedziczenia dla innych typów, takich jak struktury i wyliczenia. Nie może też służyć do "dodawania" metody do zapieczętowanej klasy.

Metody rozszerzeń umożliwiają "dodawanie" metody do istniejącego typu bez modyfikowania samego typu lub implementowania nowej metody w dziedziczonego typu. Metoda rozszerzenia nie musi również znajdować się w tym samym zestawie, co typ, który rozszerza. Metoda rozszerzenia jest wywoływana tak, jakby była zdefiniowaną składową typu.

Aby uzyskać więcej informacji, zobacz Metody rozszerzeń.

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 kontrolka await osiągnie wyrażenie w metodzie asynchronicznej, kontrolka powróci do elementu wywołującego, jeśli oczekiwane zadanie nie zostanie ukończone, a postęp w metodzie ze await słowem kluczowym zostanie zawieszony do momentu zakończenia oczekiwanego zadania. Po zakończeniu zadania wykonanie może być wznowione w metodzie .

Uwaga

Metoda asynchronizna powraca do obiektu wywołującego, gdy napotka pierwszy oczekiwany obiekt, który nie został jeszcze ukończony, lub zostanie zakończony na końcu metody asynchronicznej, w zależności od tego, co nastąpi wcześniej.

Metoda asynchronicznie zwykle ma zwracany typ Task<TResult>, TaskIAsyncEnumerable<T>lub void. Zwracany void typ jest używany głównie do definiowania procedur obsługi zdarzeń, w których wymagany jest zwracany void typ. Nie można oczekiwać metody asynchronicznej, która zwraca void wartość , a obiekt wywołujący metody zwracanej przez pustkę nie może przechwytywać wyjątków zgłaszanych przez metodę. Metoda asynchronizna może mieć dowolny typ zwracany 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>, ocena await wyrażenia w DoSomethingAsync obiekcie generuje liczbę całkowitą, 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 asynchroniczny nie może zadeklarować żadnych parametrów w parametrach, ref ani out, ale może wywoływać metody, które mają takie parametry.

Aby uzyskać więcej informacji na temat metod asynchronicznych, zobacz Asynchroniczne programowanie za pomocą asynchronicznych typów asynchronicznych i await i Async zwracanych typów.

Składowe z wyrażeniem w treści

Często istnieją definicje metod, które po prostu zwracają natychmiast wynik 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 metodę async lub jest metodą asynchroniową, treść metody musi być wyrażeniem instrukcji (takim samym jak w przypadku lambd). W przypadku właściwości i indeksatorów muszą być tylko do odczytu i nie należy używać słowa kluczowego get dostępu.

Iteratory

Iterator wykonuje iterację niestandardową w kolekcji, taką jak lista lub tablica. Iterator używa instrukcji zwrotu wydajności, aby zwrócić każdy element jeden naraz. yield return Po osiągnięciu instrukcji bieżąca lokalizacja jest zapamiętowana, aby obiekt wywołujący mógł zażądać następnego elementu w sekwencji.

Zwracany typ iteratora może mieć IEnumerablewartość , , IAsyncEnumerable<T>IEnumerable<T>, IEnumeratorlub IEnumerator<T>.

Aby uzyskać więcej informacji, zobacz Iteratory.

Zobacz też