Methoden (C#-programmeerhandleiding)

Een methode is een codeblok dat een reeks instructies bevat. Een programma zorgt ervoor dat de instructies worden uitgevoerd door de methode aan te roepen en eventuele vereiste methodeargumenten op te geven. In C# wordt elke uitgevoerde instructie uitgevoerd in de context van een methode.

De Main methode is het toegangspunt voor elke C#-toepassing en wordt aangeroepen door de Common Language Runtime (CLR) wanneer het programma wordt gestart. In een toepassing die gebruikmaakt van instructies op het hoogste niveau, wordt de Main methode gegenereerd door de compiler en bevat alle instructies op het hoogste niveau.

Notitie

In dit artikel worden benoemde methoden besproken. Zie Lambda-expressies voor informatie over anonieme functies.

Methodehandtekeningen

Methoden worden gedeclareerd in een klasse, struct of interface door het toegangsniveau op te geven, zoals public of private, optionele modifiers zoals abstract of sealed, de retourwaarde, de naam van de methode en eventuele methodeparameters. Deze onderdelen samen zijn de handtekening van de methode.

Belangrijk

Een retourtype van een methode maakt geen deel uit van de handtekening van de methode voor overbelasting van de methode. Het maakt echter deel uit van de handtekening van de methode bij het bepalen van de compatibiliteit tussen een gemachtigde en de methode waarnaar deze verwijst.

Methodeparameters staan tussen haakjes en worden gescheiden door komma's. Lege haakjes geven aan dat voor de methode geen parameters zijn vereist. Deze klasse bevat vier methoden:

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();
}

Toegang tot methoden

Het aanroepen van een methode voor een object lijkt op het openen van een veld. Voeg na de objectnaam een punt, de naam van de methode en haakjes toe. Argumenten worden tussen haakjes weergegeven en worden gescheiden door komma's. De methoden van de Motorcycle klasse kunnen daarom worden aangeroepen zoals in het volgende voorbeeld:

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);
    }
}

Methodeparameters versus argumenten

Met de methodedefinitie worden de namen en typen parameters opgegeven die vereist zijn. Bij het aanroepen van code wordt de methode aangeroepen door concrete waarden met de naam argumenten voor elke parameter te bieden. De argumenten moeten compatibel zijn met het parametertype, maar de argumentnaam (indien aanwezig) die wordt gebruikt in de aanroepende code hoeft niet hetzelfde te zijn als de parameter die in de methode is gedefinieerd. Voorbeeld:

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;
}

Doorgeven per verwijzing versus doorgeven per waarde

Wanneer een exemplaar van een waardetype wordt doorgegeven aan een methode, wordt de kopie standaard doorgegeven in plaats van het exemplaar zelf. Wijzigingen in het argument hebben daarom geen invloed op het oorspronkelijke exemplaar in de aanroepmethode. Als u een exemplaar van het waardetype wilt doorgeven op basis van verwijzing, gebruikt u het ref trefwoord. Zie Parameters voor waardetype doorgeven voor meer informatie.

Wanneer een object van een verwijzingstype wordt doorgegeven aan een methode, wordt een verwijzing naar het object doorgegeven. Dat wil gezegd, de methode ontvangt niet het object zelf, maar een argument dat de locatie van het object aangeeft. Als u een lid van het object wijzigt met behulp van deze verwijzing, wordt de wijziging weerspiegeld in het argument in de aanroepmethode, zelfs als u het object doorgeeft op waarde.

U maakt een verwijzingstype met behulp van het class trefwoord, zoals in het volgende voorbeeld wordt weergegeven:

public class SampleRefType
{
    public int value;
}

Als u nu een object doorgeeft dat op dit type is gebaseerd op een methode, wordt een verwijzing naar het object doorgegeven. In het volgende voorbeeld wordt een object van het type SampleRefType doorgegeven aan de methode 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;
}

Het voorbeeld doet in wezen hetzelfde als het vorige voorbeeld in dat er een argument op waarde wordt doorgegeven aan een methode. Maar omdat een verwijzingstype wordt gebruikt, is het resultaat anders. De wijziging die wordt aangebracht in ModifyObject het value veld van de parameter, objwijzigt ook het value veld van het argument, rtin de TestRefType methode. De TestRefType methode geeft 33 weer als uitvoer.

Zie Referentietypeparameters en verwijzingstypen doorgeven voor meer informatie over het doorgeven van verwijzingstypen op waarde.

Retourwaarden

Methoden kunnen een waarde retourneren aan de aanroeper. Als het retourtype (het type dat wordt vermeld vóór de naam van de methode) niet voidis, kan de methode de waarde retourneren met behulp van de return instructie. Een instructie met het return trefwoord gevolgd door een waarde die overeenkomt met het retourtype, retourneert die waarde aan de aanroeper van de methode.

De waarde kan worden geretourneerd naar de aanroeper op waarde of op verwijzing. Waarden worden door verwijzing naar de aanroeper geretourneerd als het ref trefwoord wordt gebruikt in de methodehandtekening en volgt elk return trefwoord. De volgende methodehandtekening en retourinstructie geven bijvoorbeeld aan dat de methode een variabele retourneert met de naam estDistance die naar de aanroeper verwijst.

public ref double GetEstimatedDistance()
{
    return ref estDistance;
}

Het return trefwoord stopt ook de uitvoering van de methode. Als het retourtype is void, is een return instructie zonder waarde nog steeds nuttig om de uitvoering van de methode te stoppen. Zonder het return trefwoord wordt de uitvoering van de methode gestopt wanneer het einde van het codeblok wordt bereikt. Methoden met een niet-ongeldig retourtype zijn vereist om het return trefwoord te gebruiken om een waarde te retourneren. Met deze twee methoden wordt bijvoorbeeld het return trefwoord gebruikt om gehele getallen te retourneren:

class SimpleMath
{
    public int AddTwoNumbers(int number1, int number2)
    {
        return number1 + number2;
    }

    public int SquareANumber(int number)
    {
        return number * number;
    }
}

Als u een waarde wilt gebruiken die wordt geretourneerd door een methode, kan de aanroepende methode overal een waarde van hetzelfde type gebruiken. U kunt de retourwaarde ook toewijzen aan een variabele. De volgende twee codevoorbeelden bereiken bijvoorbeeld hetzelfde doel:

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);

Het gebruik van een lokale variabele is in dit geval resultoptioneel om een waarde op te slaan. Het kan de leesbaarheid van de code helpen, of het kan nodig zijn als u de oorspronkelijke waarde van het argument moet opslaan voor het hele bereik van de methode.

Als u een waarde wilt gebruiken die wordt geretourneerd door verwijzing uit een methode, moet u een lokale verw-variabele declareren als u de waarde ervan wilt wijzigen. Als de Planet.GetEstimatedDistance methode bijvoorbeeld een Double waarde retourneert op basis van verwijzing, kunt u deze definiëren als een lokale verw-variabele met code zoals hieronder:

ref double distance = ref Planet.GetEstimatedDistance();

Het retourneren van een multidimensionale matrix van een methode, Mdie de inhoud van de matrix wijzigt, is niet nodig als de aanroepende functie de matrix doorgeeft aan M. U kunt de resulterende matrix retourneren voor M een goede stijl of functionele stroom van waarden, maar dit is niet nodig omdat C# alle verwijzingstypen op waarde doorgeeft en de waarde van een matrixreferentie de aanwijzer naar de matrix is. In de methode Mkunnen wijzigingen in de inhoud van de matrix worden waargenomen door code die een verwijzing naar de matrix heeft, zoals wordt weergegeven in het volgende voorbeeld:

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;
        }
    }
}

Asynchrone methoden

Met behulp van de asynchrone functie kunt u asynchrone methoden aanroepen zonder expliciete callbacks te gebruiken of uw code handmatig te splitsen over meerdere methoden of lambda-expressies.

Als u een methode markeert met de asynchrone wijziging, kunt u de wachtoperator in de methode gebruiken. Wanneer het besturingselement een wachtexpressie bereikt in de asynchrone methode, keert het besturingselement terug naar de aanroeper en wordt de voortgang in de methode opgeschort totdat de wachtende taak is voltooid. Wanneer de taak is voltooid, kan de uitvoering worden hervat in de methode.

Notitie

Een asynchrone methode keert terug naar de aanroeper wanneer het het eerste wachtende object tegenkomt dat nog niet is voltooid of het einde van de asynchrone methode bereikt, afhankelijk van wat zich het eerst voordoet.

Een asynchrone methode heeft meestal een retourtype Task<TResult>, IAsyncEnumerable<T>Taskof void. Het void retourtype wordt voornamelijk gebruikt om gebeurtenis-handlers te definiëren, waarbij een void retourtype vereist is. Een asynchrone methode die retourneert void , kan niet worden gewacht en de aanroeper van een methode voor het retourneren van ongeldige gegevens kan geen uitzonderingen vangen die de methode genereert. Een asynchrone methode kan elk taakachtig retourtype hebben.

In het volgende voorbeeld DelayAsync is een asynchrone methode met een retourtype Task<TResult>. DelayAsync heeft een return instructie die een geheel getal retourneert. Daarom moet de declaratie van DelayAsync de methode een retourtype hebben Task<int>. Omdat het retourtype isTask<int>, produceert de evaluatie van de await expressie in DoSomethingAsync een geheel getal zoals de volgende instructie laat zien: int result = await delayTask

De Main methode is een voorbeeld van een asynchrone methode met een retourtype Task. Het gaat naar de DoSomethingAsync methode en omdat deze wordt uitgedrukt met één regel, kan deze de async en await trefwoorden weglaten. Omdat DoSomethingAsync dit een asynchrone methode is, moet de taak voor de aanroep DoSomethingAsync worden gewacht, zoals in de volgende instructie wordt weergegeven: 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

Een asynchrone methode kan geen ref- of outparameters declareren, maar kan methoden aanroepen die dergelijke parameters hebben.

Zie Asynchrone programmering met asynchrone asynchrone typen en wachten en Asynchroon retourneren voor meer informatie over asynchrone methoden.

Hoofdtekstdefinities voor expressies

Het is gebruikelijk om methodedefinities te hebben die eenvoudigweg direct worden geretourneerd met het resultaat van een expressie of die één instructie hebben als hoofdtekst van de methode. Er is een syntaxissnelkoppeling voor het definiëren van dergelijke methoden met behulp van =>:

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);

Als de methode retourneert void of een asynchrone methode is, moet de hoofdtekst van de methode een instructieexpressie zijn (hetzelfde als bij lambdas). Voor eigenschappen en indexeerfuncties moeten ze alleen-lezen zijn en u gebruikt het get trefwoord accessor niet.

Iterators

Een iterator voert een aangepaste iteratie uit voor een verzameling, zoals een lijst of een matrix. Een iterator gebruikt de rendementsinstructie om elk element één voor één te retourneren. Wanneer een yield return instructie is bereikt, wordt de huidige locatie in code onthouden. De uitvoering wordt opnieuw gestart vanaf die locatie wanneer de iterator de volgende keer wordt aangeroepen.

U roept een iterator aan vanuit clientcode met behulp van een foreach-instructie .

Het retourtype van een iterator kan zijnIEnumerable, of IAsyncEnumerable<T>IEnumerable<T>IEnumeratorIEnumerator<T>.

Zie Iterators voor meer informatie.

C#-taalspecificatie

Zie de C#-taalspecificatie voor meer informatie. De taalspecificatie is de definitieve bron voor de C#-syntaxis en het gebruik.

Zie ook