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åinstruktionerMain
genereras metoden av kompilatorn och innehåller alla toppnivåinstruktioner.
Kommentar
I den här artikeln beskrivs namngivna metoder. Information om anonyma funktioner finns i Lambda-uttryck.
Metodsignaturer
Metoder deklareras i en klass, struct eller ett gränssnitt genom att ange åtkomstnivån, public
till exempel 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 ingår inte i metodens signatur för metodöverlagring. Det är dock en del av signaturen för metoden när du fastställer kompatibiliteten mellan ett ombud och den metod som 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. Klassmetoderna 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 {0}", speed);
}
}
Metodparametrar jämfört med argument
Metoddefinitionen anger namn och typer av parametrar som krävs. När du anropar kod anropar metoden innehåller 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 att skicka av 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. Om du vill skicka en värdetypsinstans efter referens använder du nyckelordet ref
. Mer information finns i Skicka parametrar av värdetyp.
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 medlem i objektet med hjälp av den här referensen återspeglas ändringen i argumentet i anropsmetoden, även om du skickar objektet efter 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
value
fältet för parametern , obj
, ändrar value
också fältet för argumentet , rt
i TestRefType
-metoden. Metoden TestRefType
visar 33 som utdata.
Mer information om hur du skickar referenstyper efter referens och värde finns i Skicka referenstypparametrar och referenstyper.
Returvärden
Metoder kan returnera ett värde till anroparen. Om returtypen (den typ som anges före metodnamnet) inte void
är kan metoden returnera värdet med hjälp av -instruktionenreturn
. En instruktion med nyckelordet return
följt av ett värde som matchar returtypen returnerar det värdet till metodanroparen.
Värdet kan returneras till anroparen efter värde eller 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 krävs för att 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);
I det här fallet result
är det valfritt att använda en lokal variabel 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 med referens från en metod måste du deklarera en lokal referensvariabel om du tänker ändra dess värde. Om Planet.GetEstimatedDistance
metoden 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 skickade matrisen till M
. Du kan returnera den resulterande matrisen från M
för 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 M
kan alla ändringar av matrisens innehåll observeras av någon 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.
Kommentar
En asynkron metod återgår till anroparen när den antingen stöter på det första väntande objektet som ännu inte har slutförts eller om den kommer till slutet av async-metoden, beroende på vilket som inträffar först.
En asynkron metod har vanligtvis en returtyp av Task<TResult>, TaskIAsyncEnumerable<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 DelayAsync
är 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>
genererar utvärderingen av await
uttrycket i DoSomethingAsync
ett heltal som följande instruktion visar: int result = await delayTask
.
Metoden Main
är ett exempel på en asynkron metod som har en returtyp av Task. Den går till DoSomethingAsync
metoden 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
vänta, 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 referens - eller utdataparametrar , men den kan anropa metoder som har sådana parametrar.
Mer information om asynkrona metoder finns i Asynkron programmering med asynkron programmering med asynkrona och väntande och Async-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 avkastningsreturinstrukturen för att returnera varje element ett i taget. När en yield return
instruktion har nåtts sparas den aktuella platsen i koden. Körningen startas om från den platsen 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.