Implementere klassemetoder og parametere

Fullført

En metode er en kodeblokk som inneholder en rekke setninger. Et program fører til at uttrykkene utføres ved å kalle metoden og angi eventuelle nødvendige metodeargumenter. I C#utføres alle utførte instruksjoner i konteksten til en metode.

Metodesignaturer

Metoder deklareres i en klasse, post eller struktur ved å angi:

  • Et valgfritt tilgangsnivå, for eksempel public eller private. Standardverdien er private.
  • Valgfrie modifikasjoner, for eksempel abstract eller sealed.
  • Returverdien, eller void hvis metoden ikke har noen.
  • Metodenavnet.
  • Alle metodeparametere. Metodeparametere er omsluttet av parenteser og er atskilt med komma. Tomme parenteser angir at metoden ikke krever noen parametere.

Disse delene fungerer sammen for å danne metodesignaturen.

Viktig

En returtype for en metode er ikke en del av signaturen til metoden med det formål å overbelaste metoden. Det er imidlertid en del av signaturen til metoden når du bestemmer kompatibiliteten mellom en representant og metoden den peker til.

Følgende eksempel definerer en klasse med navnet Motorcycle som inneholder fem metoder:


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

Klassen Motorcycle inneholder en overbelastet metode, Drive. De to Drive metodene har samme navn, men ulike parametertyper.

Aktivering av metode

Metoder kan være enten forekomst eller statiske. Du må starte et objekt for å aktivere en forekomstmetode i denne forekomsten. en forekomstmetode fungerer på denne forekomsten og dataene. Du aktiverer en statisk metode ved å referere til navnet på typen som metoden tilhører. statiske metoder fungerer ikke på forekomstdata. Forsøk på å kalle en statisk metode gjennom en objektforekomst genererer en kompilatorfeil.

Kall til en metode er som å få tilgang til et felt. Etter objektnavnet (hvis du kaller en forekomstmetode) eller typenavnet (hvis du kaller en statisk metode), legger du til et punktum, navnet på metoden og parenteser. Argumenter er oppført i parentesene og er atskilt med komma.

Metodedefinisjonen angir navnene og typene for alle parametere som kreves. Når en innringer aktiverer metoden, gir den konkrete verdier, kalt argumenter, for hver parameter. Argumentene må være kompatible med parametertypen, men argumentnavnet, hvis det brukes i kallkoden, trenger ikke å være det samme som parameteren som er angitt i metoden. I eksemplet nedenfor inneholder Square metoden én enkelt parameter av typen int kalt i. Det første metodekallet sender Square metoden en variabel av typen int kalt num; den andre, en numerisk konstant. og den tredje, et uttrykk.


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

Verdi- og referanseparametere

Typer i C# er enten verdityper eller referansetyper. Som standard sendes både verdityper og referansetyper etter verdi til en metode.

Verditypeparametere

Når en verditype sendes til en metode etter verdi, sendes en kopi av objektet i stedet for selve objektet til metoden. Endringer i objektet i den kalte metoden har derfor ingen innvirkning på det opprinnelige objektet når kontrollen returneres til anroperen.

Det følgende eksemplet sender en verditype til en metode etter verdi, og den kalte metoden forsøker å endre verditypens verdi. Den definerer en variabel av typen int, som er en verditype, initialiserer verdien til 20 og sender den til en metode kalt ModifyValue som endrer variabelverdien til 30. Når metoden returnerer, forblir imidlertid variabelens verdi uendret.


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

Når et objekt av en referansetype sendes til en metode etter verdi, sendes en referanse til objektet etter verdi. Dette betyr at metoden ikke mottar selve objektet, men et argument som angir plasseringen til objektet. Hvis du endrer et medlem av objektet ved hjelp av denne referansen, gjenspeiles endringen i objektet når kontrollen går tilbake til kallmetoden. Hvis du erstatter objektet som sendes til metoden, har det imidlertid ingen innvirkning på det opprinnelige objektet når kontrollen går tilbake til anroperen.

Følgende eksempel definerer en klasse (som er en referansetype) med navnet SampleRefType. Det gir et SampleRefType objekt, tilordner 44 til value feltet og sender objektet til ModifyObject-metoden. Dette eksemplet gjør i hovedsak det samme som det forrige eksemplet (det sender et argument etter verdi til en metode). Resultatet er imidlertid annerledes fordi en referansetype brukes i stedet for en verditype. Endringen som er gjort i ModifyObject til obj.value feltet, endrer også value feltet i argumentet, rt. Når Main-metoden viser verdien av rt ser vi at den er oppdatert til 33, som utdataene fra eksemplet viser.


public class SampleRefType
{
    public int value;
}

public static class ByRefTypeExample
{
    public static void Main()
    {
        var rt = new SampleRefType { value = 44 };
        Console.WriteLine("In Main, rt.value = {0}", rt.value);
        ModifyObject(rt);
        Console.WriteLine("Back in Main, rt.value = {0}", rt.value);
    }

    static void ModifyObject(SampleRefType obj)
    {
        obj.value = 33;
        Console.WriteLine("In ModifyObject, obj.value = {0}", obj.value);
    }
}
// The example displays the following output:
//      In Main, rt.value = 44
//      In ModifyObject, obj.value = 33
//      Back in Main, rt.value = 33

Referansetypeparametere

Du sender en parameter etter referanse når du vil endre verdien for et argument i en metode og vil gjenspeile denne endringen når kontrollen går tilbake til kallmetoden. Hvis du vil sende en parameter etter referanse, bruker du nøkkelordet ref eller out. Du kan også sende en verdi med referanse for å unngå kopiering, men likevel forhindre endringer ved hjelp av nøkkelordet in.

Følgende eksempel er identisk med det forrige, bortsett fra at verdien sendes med referanse til ModifyValue-metoden. Når verdien for parameteren endres i den ModifyValue metoden, gjenspeiles verdiendringen når kontrollen går tilbake til anroperen.


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

Et vanlig mønster som brukes av refparametere, innebærer å bytte verdiene for variabler. Du sender to variabler til en metode etter referanse, og metoden bytter innholdet. Eksemplet nedenfor bytter heltallsverdier.


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

Hvis du sender en referansetypeparameter, kan du endre verdien for selve referansen, i stedet for verdien for individuelle elementer eller felt.

Parametersamlinger

Noen ganger er kravet om at du angir nøyaktig antall argumenter til metoden restriktivt. Ved å bruke nøkkelordet params til å angi at en parameter er en parametersamling, tillater du at metoden kalles med et variabelt antall argumenter. Parameteren som er merket med nøkkelordet params må være en samlingstype, og den må være den siste parameteren i metodens parameterliste.

En innringer kan deretter aktivere metoden på fire måter for parameteren params:

  • Ved å sende en samling av riktig type som inneholder ønsket antall elementer. Eksemplet bruker et samlingsuttrykk slik at kompilatoren oppretter en passende samlingstype.
  • Ved å sende en kommadelt liste over individuelle argumenter av riktig type til metoden. Kompilatoren oppretter riktig samlingstype.
  • Ved å sende null.
  • Ved å ikke angi et argument for parametersamlingen.

Følgende eksempel definerer en metode kalt GetVowels som returnerer alle vokalene fra en parametersamling. Metoden Main illustrerer alle fire måter å aktivere metoden på. Innringere er ikke nødvendige for å angi argumenter for parametere som inkluderer params modifikatoren. I så fall er parameteren en tom samling.


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: ''

Notat

Før C# 13 kan params modifikator bare brukes med en enkeltdimensjonal matrise.

Returner verdier for metoder

Metoder kan returnere en verdi til innringeren. Hvis returtypen (typen som er oppført før metodenavnet) ikke er void, kan metoden returnere verdien ved hjelp av nøkkelordet return. En setning med nøkkelordet return etterfulgt av en variabel, konstant eller et uttrykk som samsvarer med returtypen, returnerer denne verdien til metodeoppringeren. Metoder med en ikke-aktiv returtype kreves for å bruke nøkkelordet return for å returnere en verdi. Nøkkelordet return stopper også kjøringen av metoden.

Hvis returtypen er void, er en retursetning uten en verdi fortsatt nyttig for å stoppe kjøringen av metoden. Uten return nøkkelordet slutter metoden å kjøre når den når slutten av kodeblokken.

Disse to metodene bruker for eksempel return nøkkelord til å returnere heltall:


class SimpleMath
{
    public int AddTwoNumbers(int number1, int number2) =>
        number1 + number2;

    public int SquareANumber(int number) =>
        number * number;
}

Dette eksemplet bruker uttrykksbebodde medlemmer til å tilordne returverdien for metodene. Denne syntaksen er en forkortelse for metoder som bruker én enkelt setning (uttrykk) til å beregne returverdien.

Du kan også velge å definere metodene dine med en setningstekst og en return setning:


class SimpleMathExtnsion
{
    public int DivideTwoNumbers(int number1, int number2)
    {
        return number1 / number2;
    }
}

Hvis du vil bruke en verdi som returneres fra en metode, kan kallmetoden bruke selve metodekallet hvor som helst en verdi av samme type ville være tilstrekkelig. Du kan også tilordne returverdien til en variabel. Følgende tre kodeeksempler oppnår for eksempel det samme målet:


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


result = obj2.DivideTwoNumbers(6,2);
// The result is 3.
Console.WriteLine(result);

Noen ganger vil du at metoden skal returnere mer enn én enkelt verdi. Du bruker tuppeltyper og tuppellitteraler for å returnere flere verdier. Tuppeltypen definerer datatypene for tuppelens elementer. Tuppellitteraler gir de faktiske verdiene for den returnerte tuppelen. I eksemplet nedenfor definerer (string, string, string, int) tuppeltypen som returneres av GetPersonalInfo-metoden. Uttrykket (per.FirstName, per.MiddleName, per.LastName, per.Age) er tuppellitteralen. metoden returnerer det første, midtre og familienavnet, sammen med alderen, for et PersonInfo objekt.


public (string, string, string, int) GetPersonalInfo(string id)
{
    PersonInfo per = PersonInfo.RetrieveInfoById(id);
    return (per.FirstName, per.MiddleName, per.LastName, per.Age);
}

Innringeren kan deretter bruke den returnerte tuppelen ved hjelp av følgende kode:


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

Navn kan også tilordnes tuppelelementene i tuppeltypedefinisjonen. Følgende eksempel viser en alternativ versjon av GetPersonalInfo-metoden som bruker navngitte elementer:


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

Det forrige kallet til GetPersonalInfo-metoden kan deretter endres på følgende måte:


var person = GetPersonalInfo("111111111");
Console.WriteLine($"{person.FName} {person.LName}: age = {person.Age}");

Hvis en metode tar en matrise som en parameter og endrer verdien for individuelle elementer, er det ikke nødvendig for metoden å returnere matrisen. C# sender alle referansetyper etter verdi, og verdien for en matrisereferanse er pekeren til matrisen.

Uttrykksbebodde medlemmer

Det er vanlig å ha metodedefinisjoner som returneres umiddelbart med resultatet av et uttrykk, eller som har én enkelt setning som brødtekst for metoden. Det finnes en syntakssnarvei for å definere slike metoder ved hjelp av =>:


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

Hvis metoden returnerer void eller er en asynkron metode, må metodens brødtekst være et uttrykk (samme som med lambdas). For egenskaper og indekserere må de være skrivebeskyttet, og du bruker ikke nøkkelordet get accessor.