Dela via


Metodparametrar och modifierare

Som standard skickar C# argument till funktioner efter värde. Den här metoden skickar en kopia av variabeln till metoden. För värdetyper (struct) hämtar metoden en kopia av värdet. För referenstyper (class) hämtar metoden en kopia av referensen. Du kan använda parametermodifierare för att skicka argument med referens.

Eftersom en struct är en värdetyp skickar en struct efter värde till en metod en kopia av argumentet till metoden. Metoden fungerar med den här kopian. Metoden kan inte komma åt den ursprungliga structen i anropsmetoden och kan inte ändra den. Metoden kan bara ändra kopian.

En klassinstans är en referenstyp, inte en värdetyp. När du skickar en referenstyp efter värde till en metod hämtar metoden en kopia av referensen till instansen. Båda variablerna refererar till samma objekt. Parametern är en kopia av referensen. Den anropade metoden kan inte omtilldela instansen i anropande metod. Den anropade metoden kan dock använda kopian av referensen för att komma åt instansmedlemmarna. Om den anropade metoden ändrar en instansmedlem ser anropande metoden också dessa ändringar eftersom den refererar till samma instans.

C#-språkreferensen dokumenterar den senaste versionen av C#-språket. Den innehåller även inledande dokumentation för funktioner i offentliga förhandsversioner för den kommande språkversionen.

Dokumentationen identifierar alla funktioner som först introducerades i de tre senaste versionerna av språket eller i aktuella offentliga förhandsversioner.

Tips/Råd

Information om när en funktion först introducerades i C# finns i artikeln om språkversionshistoriken för C#.

Värdeöverföring och referensöverföring

Alla exempel i det här avsnittet använder följande två record typer för att illustrera skillnaderna mellan class typer och struct typer:

public record struct Point(int X, int Y);
// This doesn't use a primary constructor because the properties implemented for `record` types are 
// readonly in record class types. That would prevent the mutations necessary for this example.
public record class Point3D
{
    public int X { get; set; }
    public int Y { get; set; }
    public int Z { get; set; }
}

Utdata från följande exempel illustrerar skillnaden mellan att överföra en structtyp som värde och att överföra en klasstyp som värde. Båda Mutate metoderna ändrar egenskapsvärden för argumentet. När parametern är en struct typ påverkar dessa ändringar en kopia av argumentets data. När parametern är en class typ påverkar dessa ändringar den instans som refereras till av argumentet:

public class PassTypesByValue
{
    public static void Mutate(Point pt)
    {
        Console.WriteLine($"\tEnter {nameof(Mutate)}:\t\t{pt}");
        pt.X = 19;
        pt.Y = 23;

        Console.WriteLine($"\tExit {nameof(Mutate)}:\t\t{pt}");
    }
    public static void Mutate(Point3D pt)
    {
        Console.WriteLine($"\tEnter {nameof(Mutate)}:\t\t{pt}");
        pt.X = 19;
        pt.Y = 23;
        pt.Z = 42;

        Console.WriteLine($"\tExit {nameof(Mutate)}:\t\t{pt}");
    }

    public static void TestPassTypesByValue()
    {
        Console.WriteLine("===== Value Types =====");

        var ptStruct = new Point { X = 1, Y = 2 };
        Console.WriteLine($"After initialization:\t\t{ptStruct}");

        Mutate(ptStruct);

        Console.WriteLine($"After called {nameof(Mutate)}:\t\t{ptStruct}");

        Console.WriteLine("===== Reference Types =====");

        var ptClass = new Point3D { X = 1, Y = 2, Z = 3 };

        Console.WriteLine($"After initialization:\t\t{ptClass}");

        Mutate(ptClass);
        Console.WriteLine($"After called {nameof(Mutate)}:\t\t{ptClass}");

        // Output:
        // ===== Value Types =====
        // After initialization:           Point { X = 1, Y = 2 }
        //         Enter Mutate:           Point { X = 1, Y = 2 }
        //         Exit Mutate:            Point { X = 19, Y = 23 }
        // After called Mutate:            Point { X = 1, Y = 2 }
        // ===== Reference Types =====
        // After initialization:           Point3D { X = 1, Y = 2, Z = 3 }
        //         Enter Mutate:           Point3D { X = 1, Y = 2, Z = 3 }
        //         Exit Mutate:            Point3D { X = 19, Y = 23, Z = 42 }
        // After called Mutate:            Point3D { X = 19, Y = 23, Z = 42 }
    }
}

Den ref modifieraren är ett sätt att skicka argument via referens till metoder. Följande kod replikerar föregående exempel, men skickar parametrar efter referens. De ändringar som görs i struct-typen visas i anropande metod när struct skickas med referens. Det finns ingen semantisk ändring när en referenstyp skickas som referens.

public class PassTypesByReference
{
    public static void Mutate(ref Point pt)
    {
        Console.WriteLine($"\tEnter {nameof(Mutate)}:\t\t{pt}");
        pt.X = 19;
        pt.Y = 23;

        Console.WriteLine($"\tExit {nameof(Mutate)}:\t\t{pt}");
    }
    public static void Mutate(ref Point3D pt)
    {
        Console.WriteLine($"\tEnter {nameof(Mutate)}:\t\t{pt}");
        pt.X = 19;
        pt.Y = 23;
        pt.Z = 42;

        Console.WriteLine($"\tExit {nameof(Mutate)}:\t\t{pt}");
    }

    public static void TestPassTypesByReference()
    {
        Console.WriteLine("===== Value Types =====");

        var pStruct = new Point { X = 1, Y = 2 };
        Console.WriteLine($"After initialization:\t\t{pStruct}");

        Mutate(ref pStruct);

        Console.WriteLine($"After called {nameof(Mutate)}:\t\t{pStruct}");

        Console.WriteLine("===== Reference Types =====");

        var pClass = new Point3D { X = 1, Y = 2, Z = 3 };

        Console.WriteLine($"After initialization:\t\t{pClass}");

        Mutate(ref pClass);
        Console.WriteLine($"After called {nameof(Mutate)}:\t\t{pClass}");

        // Output:
        // ===== Value Types =====
        // After initialization:           Point { X = 1, Y = 2 }
        //         Enter Mutate:           Point { X = 1, Y = 2 }
        //         Exit Mutate:            Point { X = 19, Y = 23 }
        // After called Mutate:            Point { X = 19, Y = 23 }
        // ===== Reference Types =====
        // After initialization:           Point3D { X = 1, Y = 2, Z = 3 }
        //         Enter Mutate:           Point3D { X = 1, Y = 2, Z = 3 }
        //         Exit Mutate:            Point3D { X = 19, Y = 23, Z = 42 }
        // After called Mutate:            Point3D { X = 19, Y = 23, Z = 42 }
    }
}

I föregående exempel ändrades egenskaperna för en parameter. En metod kan också tilldela om en parameter till ett nytt värde. Tilldelning på nytt fungerar annorlunda för strukturer och klasstyper beroende på om de skickas som värde eller som referens. I följande exempel visas hur structtyper och klasstyper beter sig, när parametrar som överförs som värde omtilldelas.

public class PassByValueReassignment
{
    public static void Reassign(Point pt)
    {
        Console.WriteLine($"\tEnter {nameof(Reassign)}:\t\t{pt}");
        pt = new Point { X = 13, Y = 29 };

        Console.WriteLine($"\tExit {nameof(Reassign)}:\t\t{pt}");
    }

    public static void Reassign(Point3D pt)
    {
        Console.WriteLine($"\tEnter {nameof(Reassign)}:\t\t{pt}");
        pt = new Point3D { X = 13, Y = 29, Z = -42 };

        Console.WriteLine($"\tExit {nameof(Reassign)}:\t\t{pt}");
    }

    public static void TestPassByValueReassignment()
    {
        Console.WriteLine("===== Value Types =====");

        var ptStruct = new Point { X = 1, Y = 2 };
        Console.WriteLine($"After initialization:\t\t{ptStruct}");

        Reassign(ptStruct);

        Console.WriteLine($"After called {nameof(Reassign)}:\t\t{ptStruct}");

        Console.WriteLine("===== Reference Types =====");

        var ptClass = new Point3D { X = 1, Y = 2, Z = 3 };

        Console.WriteLine($"After initialization:\t\t{ptClass}");

        Reassign(ptClass);
        Console.WriteLine($"After called {nameof(Reassign)}:\t\t{ptClass}");

        // Output:
        // ===== Value Types =====
        // After initialization:           Point { X = 1, Y = 2 }
        //         Enter Reassign:         Point { X = 1, Y = 2 }
        //         Exit Reassign:          Point { X = 13, Y = 29 }
        // After called Reassign:          Point { X = 1, Y = 2 }
        // ===== Reference Types =====
        // After initialization:           Point3D { X = 1, Y = 2, Z = 3 }
        //         Enter Reassign:         Point3D { X = 1, Y = 2, Z = 3 }
        //         Exit Reassign:          Point3D { X = 13, Y = 29, Z = -42 }
        // After called Reassign:          Point3D { X = 1, Y = 2, Z = 3 }
    }
}

Föregående exempel visar att när du omtilldelar en parameter till ett nytt värde visas inte ändringen från anropande metod, oavsett om typen är en värdetyp eller en referenstyp. I följande exempel visas beteendet när du omtilldelar en parameter som metoden tog emot som referens:

public class PassByReferenceReassignment
{
    public static void Reassign(ref Point pt)
    {
        Console.WriteLine($"\tEnter {nameof(Reassign)}:\t\t{pt}");
        pt = new Point { X = 13, Y = 29 };

        Console.WriteLine($"\tExit {nameof(Reassign)}:\t\t{pt}");
    }

    public static void Reassign(ref Point3D pt)
    {
        Console.WriteLine($"\tEnter {nameof(Reassign)}:\t\t{pt}");
        pt = new Point3D { X = 13, Y = 29, Z = -42 };

        Console.WriteLine($"\tExit {nameof(Reassign)}:\t\t{pt}");
    }

    public static void TestPassByReferenceReassignment()
    {
        Console.WriteLine("===== Value Types =====");

        var ptStruct = new Point { X = 1, Y = 2 };
        Console.WriteLine($"After initialization:\t\t{ptStruct}");

        Reassign(ref ptStruct);

        Console.WriteLine($"After called {nameof(Reassign)}:\t\t{ptStruct}");

        Console.WriteLine("===== Reference Types =====");

        var ptClass = new Point3D { X = 1, Y = 2, Z = 3 };

        Console.WriteLine($"After initialization:\t\t{ptClass}");

        Reassign(ref ptClass);
        Console.WriteLine($"After called {nameof(Reassign)}:\t\t{ptClass}");

        // Output:
        // ===== Value Types =====
        // After initialization:           Point { X = 1, Y = 2 }
        //         Enter Reassign:         Point { X = 1, Y = 2 }
        //         Exit Reassign:          Point { X = 13, Y = 29 }
        // After called Reassign:          Point { X = 13, Y = 29 }
        // ===== Reference Types =====
        // After initialization:           Point3D { X = 1, Y = 2, Z = 3 }
        //         Enter Reassign:         Point3D { X = 1, Y = 2, Z = 3 }
        //         Exit Reassign:          Point3D { X = 13, Y = 29, Z = -42 }
        // After called Reassign:          Point3D { X = 13, Y = 29, Z = -42 }
    }
}

Föregående exempel visar hur omtilldelning av värdet för en parameter som skickas med referens visas i den anropande kontexten.

Säker kontext för referenser och värden

Metoder kan lagra parametrarnas värden i fält. När du skickar parametrar efter värde är det vanligtvis säkert. Metoden kopierar värden och referenstyper kan nås när metoden lagrar dem i ett fält. Om parametrar skickas med referens på ett säkert sätt måste kompilatorn definiera när det är säkert att tilldela en referens till en ny variabel. För varje uttryck definierar kompilatorn en säker kontext som begränsar åtkomsten till ett uttryck eller en variabel. Kompilatorn använder två omfång: safe-context och ref-safe-context.

  • Safe-context definierar omfånget där alla uttryck kan nås på ett säkert sätt.
  • Ref-safe-context definierar omfånget där en referens till alla uttryck kan nås eller ändras på ett säkert sätt.

Informellt kan du se dessa omfång som en mekanism för att se till att koden aldrig kommer åt eller ändrar en referens som inte längre är giltig. En referens är giltig så länge den refererar till ett giltigt objekt eller en fjäder. Safe-context definierar när en variabel kan tilldelas eller omtilldelas. Ref-safe-context definierar när en variabel kan tilldelaseller omtilldelas. Tilldelning tilldelar en variabel till ett nytt värde. referenstilldelning tilldelar variabeln för att referera till en annan lagringsplats.

Referensparametrar

Om du vill skicka argument efter referens i stället för efter värde använder du någon av följande modifierare i en parameterdeklaration:

  • ref: Initiera argumentet innan du anropar metoden. Metoden kan tilldela parametern ett nytt värde, men det krävs inte.
  • out: Anropande metod behöver inte initiera argumentet innan metoden anropas. Metoden måste tilldela parametern ett värde.
  • ref readonly: Initiera argumentet innan du anropar metoden. Metoden kan inte tilldela parametern ett nytt värde.
  • in: Initiera argumentet innan du anropar metoden. Metoden kan inte tilldela parametern ett nytt värde. Kompilatorn kan skapa en tillfällig variabel för att lagra en kopia av argumentet till in parametrar.

En parameter som skickas med referens är en referensvariabel. Den har inte ett eget värde. I stället refererar den till en annan variabel som kallas dess referens. Du kan återtilldela referensvariabler, vilket ändrar deras referens.

Medlemmar i en klass kan inte ha signaturer som bara skiljer sig åt med ref, ref readonly, ineller out. Ett kompilatorfel uppstår om den enda skillnaden mellan två medlemmar av en typ är att en medlem har en ref parameter och den andra medlemmen har parametern out, ref readonlyeller in . Du kan dock överbelasta metoder när en metod har parametern ref, ref readonly, ineller out och den andra metoden har en parameter som skickas av värdet, som du ser i följande exempel. I andra situationer som kräver signaturmatchning, som att dölja eller åsidosätta, , inref, ref readonlyoch out är en del av signaturen och inte matchar varandra.

När en parameter har någon av föregående modifierare kan motsvarande argument ha en kompatibel modifierare:

  • Ett argument för en ref parameter måste innehålla ref modifieraren.
  • Ett argument för en out parameter måste innehålla out modifieraren.
  • Ett argument för en in parameter kan också innehålla in modifieraren. ref Om modifieraren används på argumentet i stället utfärdar kompilatorn en varning.
  • Ett argument för en ref readonly parameter bör innehålla antingen in eller ref modifierare, men inte båda. Om ingen av modifierarna ingår utfärdar kompilatorn en varning.

När du använder dessa modifierare beskriver de hur argumentet används:

  • ref innebär att metoden kan läsa eller skriva värdet för argumentet.
  • out innebär att metoden anger argumentets värde.
  • ref readonly innebär att metoden läser, men inte kan skriva argumentets värde. Argumentet ska skickas med referens.
  • in innebär att metoden läser, men inte kan skriva argumentets värde. Argumentet skickas med referens eller via en tillfällig variabel.

Du kan inte använda de tidigare parametermodifierarna i följande typer av metoder:

  • Asynkrona metoder som du definierar med hjälp av asynkron modifieraren.
  • Iteratormetoder, som innehåller en avkastningsretur eller yield break -instruktion.

Tilläggsmedlemmar har också begränsningar för användningen av dessa argumentnyckelord:

  • Nyckelordet out kan inte användas på det första argumentet i en tilläggsmetod.
  • Nyckelordet ref kan inte användas på det första argumentet i en tilläggsmetod när argumentet inte är en struct, eller en allmän typ som inte är begränsad till att vara en struct.
  • Nyckelorden ref readonly och in kan inte användas om inte det första argumentet är ett struct.
  • Nyckelorden ref readonly och in kan inte användas på någon allmän typ, även om de är begränsade till att vara en struct.

Egenskaper är inte variabler. Det är metoder. Du kan inte använda egenskaper som argument för ref parametrar.

ref parametermodifierare

Om du vill använda en ref parameter måste både metoddefinitionen och anropande metoden uttryckligen använda nyckelordet ref , som du ser i följande exempel. (Förutom att anropsmetoden kan utelämna ref när du gör ett COM-anrop.)

void Method(ref int refArgument)
{
    refArgument = refArgument + 44;
}

int number = 1;
Method(ref number);
Console.WriteLine(number);
// Output: 45

Du måste initiera ett argument innan du skickar det till en ref parameter.

out parametermodifierare

Om du vill använda en out parameter måste både metoddefinitionen och anropande metoden uttryckligen använda nyckelordet out . Till exempel:

int initializeInMethod;
OutArgExample(out initializeInMethod);
Console.WriteLine(initializeInMethod);     // value is now 44

void OutArgExample(out int number)
{
    number = 44;
}

Du behöver inte initiera variabler som skickas som out argument före metodanropet. Den anropade metoden måste dock tilldela ett värde innan det returneras.

Dekonstruera metoder deklarerar sina parametrar med out modifieraren för att returnera flera värden. Andra metoder kan returnera värdetupplar för flera returvärden.

Du kan deklarera en variabel i en separat instruktion innan du skickar den som ett out argument. Du kan också deklarera variabeln out i argumentlistan för metodanropet i stället för i en separat variabeldeklaration. out variabeldeklarationer ger mer kompakt, läsbar kod och förhindrar även att du oavsiktligt tilldelar ett värde till variabeln före metodanropet. I följande exempel definieras variabeln number i anropet till metoden Int32.TryParse .

string numberAsString = "1640";

if (Int32.TryParse(numberAsString, out int number))
    Console.WriteLine($"Converted '{numberAsString}' to {number}");
else
    Console.WriteLine($"Unable to convert '{numberAsString}'");
// The example displays the following output:
//       Converted '1640' to 1640

Du kan också deklarera en implicit inskriven lokal variabel.

ref readonly modifierare

Metoddeklarationen ref readonly kräver modifieraren. En modifierare på anropsplatsen är valfri. Du kan använda antingen in eller ref modifieraren. Modifieraren ref readonly är inte giltig på anropsplatsen. Den modifierare som du använder på anropsplatsen kan hjälpa dig att beskriva argumentets egenskaper. Du kan bara använda ref om argumentet är en variabel och kan skrivas. Du kan bara använda in när argumentet är en variabel. Variabeln kan vara skrivbar eller skrivskyddad. Du kan inte lägga till någon av modifierarna om argumentet inte är en variabel utan är ett uttryck. Följande exempel visar dessa villkor. Följande metod använder ref readonly modifieraren för att ange att en stor struct ska skickas med referens av prestandaskäl:

public static void ForceByRef(ref readonly OptionStruct thing)
{
    // elided
}

Du kan anropa metoden med hjälp ref av eller in modifieraren. Om du utelämnar modifieraren utfärdar kompilatorn en varning. När argumentet är ett uttryck, inte en variabel, kan du inte lägga till in eller ref modifierare, så du bör ignorera varningen:

ForceByRef(in options);
ForceByRef(ref options);
ForceByRef(options); // Warning! variable should be passed with `ref` or `in`
ForceByRef(new OptionStruct()); // Warning, but an expression, so no variable to reference

Om variabeln är en readonly variabel måste du använda in modifieraren. Kompilatorn utfärdar ett fel om du använder ref modifieraren i stället.

Modifieraren ref readonly anger att metoden förväntar sig att argumentet ska vara en variabel i stället för ett uttryck som inte är en variabel. Exempel på uttryck som inte är variabler är konstanter, metodreturvärden och egenskaper. Om argumentet inte är en variabel utfärdar kompilatorn en varning.

in parametermodifierare

Modifieraren in krävs i metoddeklarationen men onödig på anropsplatsen.

var largeStruct = new LargeStruct { Value1 = 42, Value2 = 3.14, Value3 = "Hello" };

// Using 'in' avoids copying the large struct and prevents modification
ProcessLargeStruct(in largeStruct);
Console.WriteLine($"Original value unchanged: {largeStruct.Value1}");

// Without 'in', the struct would be copied (less efficient for large structs)
ProcessLargeStructByValue(largeStruct);
Console.WriteLine($"Original value still unchanged: {largeStruct.Value1}");

void ProcessLargeStruct(in LargeStruct data)
{
    // Can read the values
    Console.WriteLine($"Processing: {data.Value1}, {data.Value2}, {data.Value3}");
    
    // Uncomment the following line to see error CS8331
    // data.Value1 = 99; // Compilation error: cannot assign to 'in' parameter
}

void ProcessLargeStructByValue(LargeStruct data)
{
    // This method receives a copy of the struct
    Console.WriteLine($"Processing copy: {data.Value1}, {data.Value2}, {data.Value3}");
    
    // Modifying the copy doesn't affect the original
    data.Value1 = 99;
}

Med in modifieraren kan kompilatorn skapa en tillfällig variabel för argumentet och skicka en skrivskyddad referens till argumentet. Kompilatorn skapar alltid en tillfällig variabel när argumentet måste konverteras, när det finns en implicit konvertering från argumenttypen eller när argumentet är ett värde som inte är en variabel. Till exempel när argumentet är ett literalvärde eller värdet som returneras från en egenskapsåtkomst. När ditt API kräver att argumentet skickas med referens väljer du ref readonly modifieraren i stället för in modifieraren.

Du kan få prestandaoptimering genom att definiera metoder med in parametrar. Vissa struct typargument kan vara stora och när du anropar metoder i snäva loopar eller kritiska kodsökvägar är kostnaden för att kopiera dessa strukturer betydande. Deklarera in parametrar för att ange att du på ett säkert sätt kan skicka argument med referens eftersom den anropade metoden inte ändrar argumentets tillstånd. Om du skickar dessa argument med referens undviker du den (potentiellt) dyra kopian. Du lägger uttryckligen in till modifieraren på anropsplatsen för att säkerställa att argumentet skickas med referens, inte efter värde. Explicit användning in har följande två effekter:

  • Om du in anger på anropsplatsen tvingar kompilatorn att välja en metod som definierats med en matchande in parameter. Annars, när två metoder skiljer sig endast i närvaro av in, är överlagringen efter värde en bättre matchning.
  • Genom att ange deklarerar indu avsikten att skicka ett argument med referens. Argumentet som används med in måste representera en plats som kan refereras direkt till. Samma allmänna regler för out och ref argument gäller: Du kan inte använda konstanter, vanliga egenskaper eller andra uttryck som skapar värden. Annars meddelar utelämnande in på anropsplatsen kompilatorn att det är bra att skapa en tillfällig variabel för att skicka med skrivskyddad referens till metoden. Kompilatorn skapar en tillfällig variabel för att övervinna flera begränsningar med in argument:
    • En tillfällig variabel tillåter kompileringstidskonstanter som in parametrar.
    • En tillfällig variabel tillåter egenskaper eller andra uttryck för in parametrar.
    • En tillfällig variabel tillåter argument där det finns en implicit konvertering från argumenttypen till parametertypen.

I alla föregående instanser skapar kompilatorn en tillfällig variabel som lagrar värdet för konstanten, egenskapen eller andra uttryck.

Följande kod illustrerar dessa regler:

static void Method(in int argument)
{
    // implementation removed
}

Method(5); // OK, temporary variable created.
Method(5L); // CS1503: no implicit conversion from long to int
short s = 0;
Method(s); // OK, temporary int created with the value 0
Method(in s); // CS1503: cannot convert from in short to in int
int i = 42;
Method(i); // passed by readonly reference
Method(in i); // passed by readonly reference, explicitly using `in`

Anta nu att en annan metod med hjälp av by-value-argument var tillgänglig. Resultatet ändras enligt följande kod:

static void Method(int argument)
{
    // implementation removed
}

static void Method(in int argument)
{
    // implementation removed
}

Method(5); // Calls overload passed by value
Method(5L); // CS1503: no implicit conversion from long to int
short s = 0;
Method(s); // Calls overload passed by value.
Method(in s); // CS1503: cannot convert from in short to in int
int i = 42;
Method(i); // Calls overload passed by value
Method(in i); // passed by readonly reference, explicitly using `in`

Det enda metodanropet där argumentet skickas med referens är det sista.

Kommentar

Föregående kod används int som argumenttyp för enkelhetens skull. Eftersom int inte är större än en referens i de flesta moderna datorer finns det ingen fördel med att skicka en enda int som en skrivskyddad referens.

params modifierare

Parametern med nyckelordet params måste vara den sista parametern i metoddeklarationen. Du kan bara använda ett params nyckelord i en metoddeklaration.

Du måste deklarera parametern params som en samlingstyp. Identifierade samlingstyper är:

Innan C# 13 måste du använda en endimensionell matris för parametern.

När du anropar en metod med en params parameter kan du skicka in:

  • En kommaavgränsad lista med argument av typen av matriselement.
  • En samling argument av den angivna typen.
  • Inga argument. Om du inte skickar några argument är listans params längd noll.

I följande exempel visas olika sätt att skicka argument till en params parameter.

public static void ParamsModifierExample(params int[] list)
{
    for (int i = 0; i < list.Length; i++)
    {
        System.Console.Write(list[i] + " ");
    }
    System.Console.WriteLine();
}

public static void ParamsModifierObjectExample(params object[] list)
{
    for (int i = 0; i < list.Length; i++)
    {
        System.Console.Write(list[i] + " ");
    }
    System.Console.WriteLine();
}

public static void TryParamsCalls()
{
    // You can send a comma-separated list of arguments of the
    // specified type.
    ParamsModifierExample(1, 2, 3, 4);
    ParamsModifierObjectExample(1, 'a', "test");

    // A params parameter accepts zero or more arguments.
    // The following calling statement displays only a blank line.
    ParamsModifierObjectExample();

    // An array argument can be passed, as long as the array
    // type matches the parameter type of the method being called.
    int[] myIntArray = { 5, 6, 7, 8, 9 };
    ParamsModifierExample(myIntArray);

    object[] myObjArray = { 2, 'b', "test", "again" };
    ParamsModifierObjectExample(myObjArray);

    // The following call causes a compiler error because the object
    // array cannot be converted into an integer array.
    //ParamsModifierExample(myObjArray);

    // The following call does not cause an error, but the entire
    // integer array becomes the first element of the params array.
    ParamsModifierObjectExample(myIntArray);
}
/*
Output:
    1 2 3 4
    1 a test

    5 6 7 8 9
    2 b test again
    System.Int32[]
*/

Överbelastningsmatchning kan orsaka tvetydighet när argumentet för en params parameter är en samlingstyp. Samlingstypen för argumentet måste konverteras till parameterns samlingstyp. När olika överlagringar ger bättre konverteringar för den parametern kan den metoden vara bättre. Men om argumentet till parametern params antingen är diskreta element eller saknas är alla överlagringar med olika params parametertyper lika med den parametern.

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