Metody (Przewodnik programowania 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 wykonana 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) podczas uruchamiania programu. W aplikacji, która używa instrukcji najwyższego poziomu, metoda jest generowana przez kompilator i zawiera wszystkie instrukcje najwyższego poziomu.
Uwaga
W tym artykule omówiono nazwane metody. Aby uzyskać informacje o funkcjach anonimowych, zobacz Wyrażenia lambda.
Sygnatury metod
Metody są deklarowane w klasie, strukturze lub interfejsie przez określenie poziomu dostępu,takiego jak lub , modyfikatorów opcjonalnych, takich jak lub sealed, wartości zwracanej, nazwy metody i dowolnych parametrów metody. Te części razem są podpisem metody .
Ważne
Zwracany typ metody nie jest częścią podpisu metody na potrzeby przeciążania metody. Jednak jest on częścią podpisu metody podczas określania zgodności między delegatem a metodą, na która wskazuje.
Parametry metody są ujęte w nawiasy i są oddzielone przecinkami. Puste nawiasy wskazują, że metoda nie wymaga parametrów. Ta klasa zawiera cztery metody:
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 must implement this.
public abstract double GetTopSpeed();
}
Dostęp do metody
Wywoływanie metody na obiekcie jest podobne do uzyskiwania dostępu do pola. Po nazwie obiektu dodaj okres, nazwę metody i nawiasy. Argumenty są wymienione w nawiasach i są oddzielone przecinkami. W związku z tym metody Motorcycle klasy można nazwać tak jak w poniższym przykładzie:
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);
}
}
Parametry metody a argumenty
Definicja metody określa nazwy i typy wymaganych parametrów. Podczas wywoływania kodu metoda wywołuje konkretne wartości nazywane argumentami dla każdego parametru. Argumenty muszą być zgodne z typem parametru, ale nazwa argumentu (jeśli taka jest) używana w kodzie wywołującym nie musi być taka sama jak parametr o nazwie zdefiniowany w metodzie . Na przykład:
public void Caller()
{
int numA = 4;
// Call with an int variable.
int productA = Square(numA);
int numB = 32;
// Call with another int variable.
int productB = Square(numB);
// Call with an integer literal.
int productC = Square(12);
// Call with an expression that evaluates to int.
productC = Square(productA * 3);
}
int Square(int i)
{
// Store input argument in a local variable.
int input = i;
return input * input;
}
Przekazywanie według odwołania a przekazywanie według wartości
Domyślnie, gdy wystąpienie typu wartości jest przekazywane do metody, jego kopia jest przekazywana zamiast samego wystąpienia. W związku z tym zmiany w argumentie nie mają wpływu na oryginalne wystąpienie w metodzie wywołującej. Aby przekazać wystąpienie typu wartości przez odwołanie, użyj słowa kluczowego ref . Aby uzyskać więcej informacji, zobacz Przekazywanie Value-Type parametrów.
Gdy obiekt typu referencyjnego jest przekazywany do metody, przekazywane jest odwołanie do obiektu. Oznacza to, że metoda odbiera nie sam obiekt, ale argument, który wskazuje lokalizację obiektu. Jeśli zmienisz członka obiektu przy użyciu tego odwołania, zmiana zostanie odzwierciedlona w argumentie w metodzie wywołującej, nawet jeśli przekażemy obiekt przez wartość.
Typ odwołania tworzy się przy użyciu słowa kluczowego class , jak pokazano w poniższym przykładzie:
public class SampleRefType
{
public int value;
}
Teraz, jeśli przekażesz obiekt oparty na tym typie do metody, zostanie przekazane odwołanie do obiektu. Poniższy przykład przekazuje obiekt typu do SampleRefType metody ModifyObject:
public static void TestRefType()
{
SampleRefType rt = new SampleRefType();
rt.value = 44;
ModifyObject(rt);
Console.WriteLine(rt.value);
}
static void ModifyObject(SampleRefType obj)
{
obj.value = 33;
}
Przykład zasadniczo robi to samo, co w poprzednim przykładzie, ponieważ przekazuje argument przez wartość do metody. Jednak ze względu na to, że jest używany typ referencyjny, wynik jest inny. Modyfikacja w polu ModifyObjectvalue parametru , objvalue również zmienia pole argumentu , rtw TestRefType metodzie . Metoda TestRefType wyświetla 33 jako dane wyjściowe.
Aby uzyskać więcej informacji na temat przekazywania typów referencyjnych według odwołania i wartości, zobacz Przekazywanie Reference-Type itypy referencyjne.
Wartości zwracane
Metody mogą zwracać wartość do wywołującego. Jeśli zwracany typ (typ wymieniony przed nazwą metody) voidnie ma wartości , metoda może zwrócić wartość przy użyciu void . Instrukcja ze słowem kluczowym return , po której następuje wartość, która odpowiada typowi zwracanemu, zwróci tę wartość do obiektu wywołującego metodę.
Wartość może być zwracana do wywołującego przez wartość lub, począwszy od języka C# 7.0, przez odwołanie. Wartości są zwracane do wywołującego przez odwołanie, ref jeśli słowo kluczowe jest używane w sygnaturze metody i następuje po nim każde słowo kluczowe return . Na przykład następująca podpis metody i instrukcja return wskazują, że metoda estDistance zwraca zmienną o nazwie przez odwołanie do wywołującego.
public ref double GetEstimatedDistance()
{
return ref estDistance;
}
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 return kluczowego metoda przestanie być wykonywana, gdy osiągnie koniec bloku kodu. Metody z typem zwracanej wartości niepustej są wymagane do użycia słowa kluczowego return w celu zwrócenia wartości. 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)
{
return number1 + number2;
}
public int SquareANumber(int number)
{
return number * number;
}
}
Aby użyć wartości zwróconej z metody, metoda wywołująca może użyć samego wywołania metody wszędzie tam, gdzie wartość tego samego typu będzie wystarczająca. Możesz również przypisać wartość zwracaną do zmiennej. Na przykład następujące dwa przykłady kodu osiągną 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.
Aby użyć wartości zwracanej przez odwołanie z metody, należy zadeklarować zmienną lokalną ref , jeśli zamierzasz zmodyfikować jej wartość. Jeśli na przykład metoda Planet.GetEstimatedDistance zwraca wartość Double według odwołania, można ją zdefiniować jako zmienną lokalną ref z kodem w następujący sposób:
ref int distance = Planet.GetEstimatedDistance();
Zwracanie tablicy wielowymiarowej z metody , Mktóra modyfikuje zawartość tablicy, nie jest konieczne, jeśli funkcja wywołująca przekazała tablicę do metody M. Wynikową M tablicę można zwrócić z , aby uzyskać dobry styl lub funkcjonalny przepływ wartości, ale nie jest to konieczne, ponieważ język C# przekazuje wszystkie typy referencyjne według wartości, a wartość odwołania do tablicy jest wskaźnikiem do tablicy. W metodzie Mwszelkie zmiany zawartości tablicy są widoczne dla dowolnego kodu, który ma odwołanie do tablicy, jak pokazano w poniższym przykładzie:
static void Main(string[] args)
{
int[,] matrix = new int[2, 2];
FillMatrix(matrix);
// matrix is now full of -1
}
public static void FillMatrix(int[,] matrix)
{
for (int i = 0; i < matrix.GetLength(0); i++)
{
for (int j = 0; j < matrix.GetLength(1); j++)
{
matrix[i, j] = -1;
}
}
}
Metody asynchroniczne
Za pomocą funkcji asynchronicznej można wywoływać metody asynchroniczne bez użycia jawnych wywołań zwrotnych lub ręcznego dzielenia kodu na wiele metod lub wyrażeń lambda.
Jeśli oznaczysz metodę za pomocą modyfikatora asynchronicznego , możesz użyć operatora await w metodzie . Gdy kontrolka osiągnie wyrażenie await w metodzie asynchronicznej, kontrolka powraca do wywołującego, a postęp w metodzie jest zawieszony do momentu ukończenia oczekiwanego zadania. Po zakończeniu zadania wykonywanie można wznowić w metodzie .
Uwaga
Metoda asynchroniczna wraca do obiektu wywołującego, gdy napotka pierwszy oczekiwany obiekt, który nie jest jeszcze ukończony, lub do końca metody asynchronicznej, w zależności od tego, co nastąpi najpierw.
Metoda asynchroniczna zwykle ma zwracany typ Task<TResult>, Tasklub IAsyncEnumerable<T>void. Zwracany void typ jest używany głównie do definiowania programów obsługi zdarzeń, gdzie wymagany void jest zwracany typ. Nie można void czekać na metodę asynchroniczną, która zwraca wartość , a element wywołujący metodę zwracaną przez void nie może przechwycić wyjątków zgłaszanych przez metodę. Począwszy od języka C# 7.0, metoda asynchroniczna może mieć zwracany typ podobny do zadania.
W poniższym przykładzie metoda DelayAsync jest metodą asynchroniczną, która ma zwracany typ .Task<TResult> DelayAsync Ma instrukcje return , które zwraca liczbę całkowitą. Dlatego deklaracja metody musi DelayAsync mieć zwracany typ Task<int>. Ponieważ zwracany typ to Task<int>, ocena awaitDoSomethingAsync wyrażenia w pliku generuje liczbę całkowitą, jak pokazano w poniższej instrukcji: int result = await delayTask.
Metoda Main jest przykładem metody asynchronicznej, która ma zwracany typ .Task Przechodzi do metody DoSomethingAsync , a ponieważ jest wyrażona za pomocą jednego wiersza, może pominąć słowa kluczowe async i await . Ponieważ DoSomethingAsync metoda jest metodą asynchroniczną, zadanie dla DoSomethingAsync wywołania metody musi być oczekiwane, jak pokazano w poniższej instrukcji: await DoSomethingAsync();.
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 ref ani out , ale może wywołać metody, które mają takie parametry.
Aby uzyskać więcej informacji na temat metod asynchronicznych, zobacz Asynchronous programming with async and await and Async return types (Programowanie asynchroniczne z typami zwracanych async i await).
Definicje treści wyrażeń
Często definicje metod są po prostu zwracane natychmiast z wynikiem wyrażenia lub które mają pojedynczą instrukcje jako treść metody. Istnieje skrót składniowy do definiowania takich metod przy użyciu polecenia =>:
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 wartość void lub jest metodą asynchroniczną, treść metody musi być wyrażeniem instrukcji (tak samo jak w przypadku wyrażeń lambda). W przypadku właściwości i indeksatorów muszą być tylko do odczytu, a nie należy używać słowa kluczowego get accessor.
Iteratory
Iterator wykonuje niestandardową iterację na kolekcji, takiej jak lista lub tablica. Iterator używa instrukcji yield return , aby zwracać każdy element po jednym na raz. Po osiągnięciu yield return zostanie osiągnięta bieżąca lokalizacja w kodzie. Wykonanie jest ponownie uruchomione z tej lokalizacji, gdy iterator zostanie wywołany następnym razem.
Iterator jest wywołany z kodu klienta przy użyciu instrukcji foreach .
Zwracany typ iteratora może być IEnumerable, IEnumerable<T>, IEnumeratorlub IEnumerator<T>.
Aby uzyskać więcej informacji, zobacz Iteratory.
specyfikacja języka C#
Aby uzyskać więcej informacji, zobacz Specyfikacja języka C#. Specyfikacja języka jest ostatecznym źródłem informacji o składni i użyciu języka C#.