Dela via


Metoder (C#-programmeringsguide)

En metod är ett kodblock som innehåller en serie instruktioner. Ett program gör att uttrycken körs genom att anropa metoden och ange eventuella obligatoriska metodargument. I C# utförs varje körd instruktion i kontexten för en metod.

Metoden Main är startpunkten för varje C#-program och anropas av CLR (Common Language Runtime) när programmet startas. I ett program som använder toppnivåinstruktionergenereras metoden Main av kompilatorn och innehåller alla toppnivåinstruktioner.

Anmärkning

I den här artikeln beskrivs namngivna metoder. Information om anonyma funktioner finns i Lambda-uttryck.

Metodsignaturer

Metoder deklareras i en -klass, structeller gränssnitt genom att ange åtkomstnivån, till exempel public eller private, valfria modifierare som abstract eller sealed, returvärdet, namnet på metoden och eventuella metodparametrar. Dessa delar tillsammans är metodens signatur.

Viktigt!

En returtyp för en metod är inte en del av metodens signatur vid metodöverlagring. Det är dock en del av signaturen för metoden när du fastställer kompatibiliteten mellan en delegering och den metod den pekar på.

Metodparametrar omges av parenteser och avgränsas med kommatecken. Tomma parenteser anger att metoden inte kräver några parametrar. Den här klassen innehåller fyra metoder:

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

Metodåtkomst

Att anropa en metod för ett objekt är som att komma åt ett fält. Efter objektnamnet lägger du till en punkt, namnet på metoden och parenteser. Argument visas inom parenteserna och avgränsas med kommatecken. Metoderna för klassen Motorcycle kan därför anropas som i följande exempel:

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 {speed}");
    }
}

Metodparametrar jämfört med argument

Metoddefinitionen anger namn och typer av parametrar som krävs. När anropande kod anropar metoden, ger den konkreta värden som kallas argument för varje parameter. Argumenten måste vara kompatibla med parametertypen, men argumentnamnet (om det finns något) som används i anropskoden behöver inte vara samma som parametern med namnet som definierats i metoden. Till exempel:

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

Skicka med referens jämfört med skicka med värde

När en instans av en värdetyp skickas till en metod skickas som standard dess kopia i stället för själva instansen. Därför har ändringar i argumentet ingen effekt på den ursprungliga instansen i anropsmetoden. För att skicka en värdetypsinstans via referens använder du nyckelordet ref. För mer information, se Överföra Value-Type parametrar.

När ett objekt av en referenstyp skickas till en metod skickas en referens till objektet. Metoden tar alltså inte emot själva objektet utan ett argument som anger objektets plats. Om du ändrar en egenskap i objektet med hjälp av den här referensen, återspeglas ändringen i argumentet i den metod som anropar, även om du skickar objektet som ett värde.

Du skapar en referenstyp med hjälp av nyckelordet class, som följande exempel visar:

public class SampleRefType
{
    public int value;
}

Om du skickar ett objekt som baseras på den här typen till en metod skickas nu en referens till objektet. I följande exempel skickas ett objekt av typen SampleRefType till metoden 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;
}

Exemplet gör i stort sett samma sak som i föregående exempel eftersom det skickar ett argument efter värde till en metod. Men eftersom en referenstyp används är resultatet annorlunda. Den ändring som görs i ModifyObject i fältet value för parametern obj, ändrar också argumentets value fält, rt, i metoden TestRefType. Metoden TestRefType visar 33 som utdata.

Mer information om hur du skickar referenstyper efter referens och värde finns i Passing Reference-Type Parameters and Reference Types.

Returnera värden

Metoder kan returnera ett värde till anroparen. Om returtypen (den typ som anges före metodnamnet) inte är voidkan metoden returnera värdet med hjälp av return-instruktionen. En instruktion med nyckelordet return följt av ett värde som matchar returtypen returnerar värdet till metodanroparen.

Värdet kan returneras till anroparen genom värde eller med referens. Värden returneras till anroparen som referens om nyckelordet ref används i metodsignaturen och det följer varje return nyckelord. Följande metodsignatur och retur-instruktion anger till exempel att metoden returnerar en variabel med namnet estDistance med referens till anroparen.

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

Nyckelordet return stoppar även körningen av metoden. Om returtypen är voidär en return instruktion utan värde fortfarande användbar för att stoppa körningen av metoden. Utan nyckelordet return slutar metoden att köras när den når slutet av kodblocket. Metoder med en icke-void returtyp måste använda nyckelordet return för att returnera ett värde. Dessa två metoder använder till exempel nyckelordet return för att returnera heltal:

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

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

Om du vill använda ett värde som returneras från en metod kan anropsmetoden använda själva metodanropet var som helst där ett värde av samma typ skulle vara tillräckligt. Du kan också tilldela returvärdet till en variabel. Följande två kodexempel uppnår till exempel samma 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);

Det är valfritt att använda en lokal variabel, i det här fallet result, för att lagra ett värde. Det kan underlätta kodens läsbarhet, eller så kan det vara nödvändigt om du behöver lagra det ursprungliga värdet för argumentet för hela metodens omfång.

Om du vill använda ett värde som returneras av en referens från en metod måste du deklarera en referens lokal variabel om du tänker ändra dess värde. Om metoden Planet.GetEstimatedDistance till exempel returnerar ett Double värde efter referens kan du definiera det som en lokal referensvariabel med kod som följande:

ref double distance = ref Planet.GetEstimatedDistance();

Att returnera en flerdimensionell matris från en metod, M, som ändrar matrisens innehåll är inte nödvändigt om den anropande funktionen redan har skickat matrisen till M. Du kan returnera den resulterande matrisen från M för ett bra format eller funktionellt flöde av värden, men det är inte nödvändigt eftersom C# skickar alla referenstyper efter värde, och värdet för en matrisreferens är pekaren till matrisen. I metoden Mkan alla ändringar av matrisens innehåll observeras av all kod som har en referens till matrisen, enligt följande exempel:

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

Asynkrona metoder

Genom att använda funktionen async kan du anropa asynkrona metoder utan att använda explicita motringningar eller manuellt dela upp koden mellan flera metoder eller lambda-uttryck.

Om du markerar en metod med asynkron modifierare kan du använda await-operatorn i -metoden. När kontrollen når ett inväntningsuttryck i async-metoden återgår kontrollen till anroparen och förloppet i metoden pausas tills den väntande aktiviteten har slutförts. När uppgiften är klar kan körningen återupptas i metoden.

Anmärkning

En asynkron funktion återgår till anroparen när den antingen stöter på det första väntade objektet som ännu inte har slutförts eller den kommer till slutet av async-metoden, vilket som inträffar först.

En asynkron metod har vanligtvis en returtyp av Task<TResult>, Task, IAsyncEnumerable<T>eller void. Returtypen void används främst för att definiera händelsehanterare, där en void returtyp krävs. Det går inte att vänta på en asynkron metod som returnerar void och anroparen för en void-returning-metod kan inte fånga undantag som metoden genererar. En asynkron metod kan ha valfri typ av aktivitetsliknande retur.

I följande exempel är DelayAsync en asynkron metod som har en returtyp av Task<TResult>. DelayAsync har en return-instruktion som returnerar ett heltal. Därför måste metoddeklarationen för DelayAsync ha en returtyp av Task<int>. Eftersom returtypen är Task<int>resulterar utvärderingen av uttrycket await i DoSomethingAsync i ett heltal, vilket följande sats visar: int result = await delayTask.

Metoden Main är ett exempel på en asynkron metod som har en returtyp av Task. Den går till metoden DoSomethingAsync och eftersom den uttrycks med en enda rad kan den utelämna nyckelorden async och await. Eftersom DoSomethingAsync är en asynkron metod måste uppgiften för anropet till DoSomethingAsync inväntas, som följande instruktion visar: 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

En asynkron metod kan inte deklarera några ref eller out parametrar, men den kan anropa metoder som har sådana parametrar.

För mer information om asynkrona metoder, se Asynkron programmering med async och await och Asynkrona returtyper.

Uttryckstextdefinitioner

Det är vanligt att ha metoddefinitioner som helt enkelt returneras omedelbart med resultatet av ett uttryck, eller som har en enda -instruktion som brödtext för metoden. Det finns en syntaxgenväg för att definiera sådana metoder med hjälp 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);

Om metoden returnerar void eller är en asynkron metod måste metodens brödtext vara ett uttryck (samma som med lambdas). För egenskaper och indexerare måste de vara skrivskyddade och du använder inte nyckelordet get accessor.

Iteratorer

En iterator utför en anpassad iteration över en samling, till exempel en lista eller en matris. En iterator använder yield return-satsen för att returnera varje element, ett i taget. När en yield return-instruktion nås sparas den aktuella platsen i koden. Körningen startas om från den positionen när iteratorn anropas nästa gång.

Du anropar en iterator från klientkoden med hjälp av en foreach-instruktion.

Returtypen för en iterator kan vara IEnumerable, IEnumerable<T>, IAsyncEnumerable<T>, IEnumeratoreller IEnumerator<T>.

Mer information finns i Iteratorer.

Språkspecifikation för C#

Mer information finns i C#-språkspecifikationen. Språkspecifikationen är den slutgiltiga källan för C#-syntax och -användning.

Se även