Implementer klassemetoder og -parametre

Fuldført

En metode er en kodeblok, der indeholder en række sætninger. Et program medfører, at sætningerne udføres ved at kalde metoden og angive eventuelle obligatoriske metodeargumenter. I C#udføres alle udførte instruktioner i konteksten af en metode.

Metodesignaturer

Metoder defineres i en klasse, post eller struktur ved at angive:

  • Et valgfrit adgangsniveau, f.eks. public eller private. Standarden er private.
  • Valgfrie modifikatorer, f.eks. abstract eller sealed.
  • Returværdien eller void, hvis metoden ikke har nogen.
  • Metodenavnet.
  • Alle metodeparametre. Metodeparametre er omsluttet af parenteser og er adskilt af kommaer. Tomme parenteser angiver, at metoden ikke kræver nogen parametre.

Disse dele arbejder sammen om at danne metodesignaturen.

Vigtig

En returtype for en metode er ikke en del af signaturen for metoden med henblik på overbelastning af metoden. Det er dog en del af signaturen for metoden, når det bestemmes, om en stedfortræder er kompatibel med den metode, den peger på.

I følgende eksempel defineres en klasse med navnet Motorcycle, der indeholder 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 indeholder en overbelastet metode, Drive. De to Drive metoder har samme navn, men forskellige parametertyper.

Aktivering af metode

Metoder kan enten være forekomst eller statiske. Du skal instantiere et objekt for at aktivere en forekomstmetode på den pågældende forekomst. en forekomstmetode fungerer på den pågældende forekomst og dens data. Du aktiverer en statisk metode ved at referere til navnet på den type, som metoden tilhører. statiske metoder fungerer ikke på forekomstdata. Forsøg på at kalde en statisk metode via en objektforekomst genererer en compilerfejl.

Kald af en metode svarer til at få adgang til et felt. Efter objektnavnet (hvis du kalder en forekomstmetode) eller typenavnet (hvis du kalder en statisk metode), skal du tilføje et punktum, navnet på metoden og parenteser. Argumenter er angivet i parenteserne og er adskilt af kommaer.

Metodedefinitionen angiver navnene og typerne af de parametre, der kræves. Når en kalder aktiverer metoden, leverer den konkrete værdier, kaldet argumenter, for hver parameter. Argumenterne skal være kompatible med parametertypen, men argumentnavnet behøver ikke at være det samme som den parameter, der er defineret i metoden, hvis det bruges i kaldekoden. I følgende eksempel indeholder metoden Square en enkelt parameter af typen int med navnet i. Det første metodekald overfører metoden Square en variabel af typen int med navnet num; den anden, en numerisk konstant; og det tredje er et udtryk.


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

Værdi- og referenceparametre

Typer i C# er enten værdityper eller referencetyper. Som standard overføres både værdityper og referencetyper af værdien til en metode.

Parametre for værditype

Når en værditype overføres til en metode efter værdi, overføres der en kopi af objektet i stedet for selve objektet til metoden . Ændringer af objektet i den kaldte metode har derfor ingen indvirkning på det oprindelige objekt, når kontrolelementet vender tilbage til kalderen.

I følgende eksempel overføres en værditype til en metode efter værdi, og den kaldte metode forsøger at ændre værditypens værdi. Den definerer en variabel af typen int, som er en værditype, initialiserer dens værdi til 20 og overfører den til en metode med navnet ModifyValue, der ændrer variablens værdi til 30. Når metoden returnerer, forbliver variablens værdi uændret.


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 af en referencetype overføres til en metode efter værdi, overføres en reference til objektet af værdien. Det vil sige, at metoden ikke modtager selve objektet, men et argument, der angiver objektets placering. Hvis du ændrer et medlem af objektet ved hjælp af denne reference, afspejles ændringen i objektet, når kontrolelementet vender tilbage til kaldemetoden. Erstatning af det objekt, der overføres til metoden, har dog ingen indvirkning på det oprindelige objekt, når kontrolelementet vender tilbage til kalderen.

I følgende eksempel defineres en klasse (som er en referencetype) med navnet SampleRefType. Det instantierer et SampleRefType-objekt, tildeler 44 til dets value felt og overfører objektet til metoden ModifyObject. Dette eksempel gør stort set det samme som i det forrige eksempel (det overfører et argument efter værdi til en metode). Resultatet er dog anderledes, fordi der bruges en referencetype i stedet for en værditype. Den ændring, der er foretaget i ModifyObject af feltet obj.value, ændrer også value felt i argumentet rt. Når Main-metoden viser værdien af rt kan vi se, at den er blevet opdateret til 33, som outputtet 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

Parametre for referencetype

Du overfører en parameter ved hjælp af en reference, når du vil ændre værdien af et argument i en metode og vil afspejle ændringen, når kontrolelementet vender tilbage til kaldemetoden. Hvis du vil overføre en parameter efter reference, skal du bruge nøgleordet ref eller out. Du kan også overføre en værdi ved hjælp af en reference for at undgå kopiering, men stadig forhindre ændringer ved hjælp af nøgleordet in.

Følgende eksempel er identisk med det forrige, bortset fra at værdien overføres som reference til metoden ModifyValue. Når værdien af parameteren ændres i metoden ModifyValue, afspejles ændringen i værdien, når kontrolelementet vender tilbage til kalderen.


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 almindeligt mønster, der bruges af referenceparametre, omfatter ombytning af værdierne for variabler. Du overfører to variabler til en metode efter reference, og metoden bytter deres indhold. I følgende eksempel ombyttes heltalsværdier.


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 overfører en referencetypeparameter, kan du ændre selve referenceværdien i stedet for værdien af de enkelte elementer eller felter.

Parametersamlinger

Nogle gange er kravet om, at du angiver det nøjagtige antal argumenter til din metode, restriktivt. Når du bruger nøgleordet params til at angive, at en parameter er en parametersamling, tillader du, at metoden kaldes med et variabelt antal argumenter. Parameteren, der er mærket med nøgleordet params, skal være en samlingstype, og den skal være den sidste parameter på metodens parameterliste.

En kalder kan derefter aktivere metoden på en af fire måder for parameterparameteren:

  • Ved at overføre en samling af den relevante type, der indeholder det ønskede antal elementer. I eksemplet bruges et samlingsudtryk, så compileren opretter en passende samlingstype.
  • Ved at overføre en kommasepareret liste over individuelle argumenter af den relevante type til metoden. Compileren opretter den relevante samlingstype.
  • Ved at overføre null.
  • Ved ikke at angive et argument til parametersamlingen.

I følgende eksempel defineres en metode med navnet GetVowels, der returnerer alle vokalerne fra en parametersamling. Metoden Main illustrerer alle fire måder at aktivere metoden på. Opkaldere er ikke påkrævet for at angive nogen argumenter for parametre, der indeholder params-modifikatoren. I så fald 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: ''

Seddel

Før C# 13 kan den params modifikator kun bruges sammen med en enkeltdimensionel matrix.

Returner værdier for metoder

Metoder kan returnere en værdi til kalderen. Hvis returtypen (den type, der er angivet før metodenavnet) ikke er void, kan metoden returnere værdien ved hjælp af nøgleordet return. En sætning med nøgleordet return efterfulgt af en variabel, en konstant eller et udtryk, der svarer til returtypen, returnerer den pågældende værdi til metodekalderen. Metoder med en returtype, der ikke er et id, skal bruge nøgleordet return til at returnere en værdi. Nøgleordet return stopper også udførelsen af metoden.

Hvis returtypen er void, er en retursætning uden en værdi stadig nyttig til at stoppe udførelsen af metoden . Uden nøgleordet return stopper metoden med at køre, når den når slutningen af kodeblokken.

Disse to metoder bruger f.eks. nøgleordet return til at returnere heltal:


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

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

I dette eksempel bruges udtryksdelte medlemmer til at tildele returværdien for metoderne. Denne syntaks er en oversigt over metoder, der bruger en enkelt sætning (udtryk) til at beregne returværdien.

Du kan også vælge at definere dine metoder med brødteksten i en sætning og en return sætning:


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

Hvis du vil bruge en værdi, der returneres fra en metode, kan den kaldende metode bruge selve metoden til at kalde sig selv et vilkårligt sted, hvor en værdi af samme type ville være tilstrækkelig. Du kan også tildele returværdien til en variabel. Følgende tre kodeeksempler opnår f.eks. det samme mål:


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

Nogle gange vil du gerne have, at din metode returnerer mere end en enkelt værdi. Du bruger tupeltyper og tupelkonstanter til at returnere flere værdier. Tupeltypen definerer datatyperne for tupelens elementer. Tuplekonstanter angiver de faktiske værdier for den returnerede tupel. I følgende eksempel definerer (string, string, string, int) den tupeltype, der returneres af metoden GetPersonalInfo. Udtrykket (per.FirstName, per.MiddleName, per.LastName, per.Age) er tupelkonstanten. metoden returnerer det første, midterste og familienavn sammen med alderen på 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);
}

Den, der ringer op, kan derefter bruge den returnerede tupel ved hjælp af følgende kode:


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

Navne kan også tildeles til tupelelementerne i definitionen af tupeltypen. I følgende eksempel vises en alternativ version af metoden GetPersonalInfo, der bruger navngivne 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 kald til metoden GetPersonalInfo kan derefter ændres på følgende måde:


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

Hvis en metode bruger en matrix som en parameter og ændrer værdien af individuelle elementer, er det ikke nødvendigt for metoden at returnere matrixen. C# overfører alle referencetyper efter værdi, og værdien af en matrixreference er markøren til matrixen.

Udtryks-bodied-medlemmer

Det er almindeligt at have metodedefinitioner, der returneres med det samme med resultatet af et udtryk, eller som har en enkelt sætning som brødteksten i metoden. Der er en syntaksgenvej til definition af sådanne metoder ved hjælp af =>:


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, skal metodens brødtekst være et sætningsudtryk (samme som med lambdas). For egenskaber og indeksering skal de være skrivebeskyttede, og du bruger ikke nøgleordet get accessor.