Delen via


Methodeparameters en modificatoren

Standaard worden argumenten in C# doorgegeven aan functies op waarde. Dit betekent dat een kopie van de variabele wordt doorgegeven aan de methode. Voor waardetypen wordtstruct een kopie van de waarde doorgegeven aan de methode. Voor verwijzingstypen wordtclass een kopie van de verwijzing doorgegeven aan de methode. Met parameteraanpassingen kunt u argumenten doorgeven op basis van verwijzing.

Omdat een struct een waardetype is, ontvangt de methode een kopie van het argument en werkt daarop wanneer u een struct per waarde aan een methode doorgeeft. De methode heeft geen toegang tot de oorspronkelijke struct in de aanroepmethode en kan deze daarom op geen enkele manier wijzigen. De methode kan alleen de kopie wijzigen.

Een klasse-exemplaar is een verwijzingstype dat geen waardetype is. Wanneer een verwijzingstype als waarde wordt doorgegeven aan een methode, ontvangt de methode een kopie van de verwijzing naar het exemplaar. Beide variabelen verwijzen naar hetzelfde object. De parameter is een kopie van de verwijzing. De aangeroepen methode kan het exemplaar niet opnieuw toewijzen in de aanroepmethode. De aangeroepen methode kan echter de kopie van de verwijzing gebruiken om toegang te krijgen tot de leden van het exemplaar. Als de aangeroepen methode een exemplaarlid wijzigt, ziet de aanroepmethode deze wijzigingen ook omdat deze verwijst naar hetzelfde exemplaar.

Doorgeven via waarde en doorgeven via referentie

In alle voorbeelden in deze sectie worden de volgende twee record typen gebruikt om de verschillen tussen class typen en struct typen te illustreren:

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

De uitvoer van het volgende voorbeeld illustreert het verschil tussen het doorgeven van een structtype per waarde en het doorgeven van een klassetype per waarde. Beide Mutate methoden wijzigen eigenschapswaarden van het argument. Wanneer de parameter een struct type is, worden deze wijzigingen aangebracht in een kopie van de gegevens van het argument. Wanneer de parameter een class type is, worden deze wijzigingen aangebracht in het exemplaar waarnaar wordt verwezen door het argument:

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

De ref modifier is een manier om argumenten door middel van verwijzing door te geven aan methoden. De volgende code volgt het voorgaande voorbeeld, maar geeft parameters door via referentie. De wijzigingen in het struct type zijn zichtbaar in de oproepmethode wanneer de struct door middel van een verwijzing wordt doorgegeven. Er is geen semantische wijziging wanneer een referentietype via een referentie wordt doorgegeven.

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

In de voorgaande voorbeelden zijn de eigenschappen van een parameter gewijzigd. Een methode kan ook een parameter opnieuw toewijzen aan een nieuwe waarde. Herindeling werkt verschillend voor struct en class typen als ze worden doorgegeven via waarde of referentie. In het volgende voorbeeld ziet u hoe structtypen en klassetypen zich gedragen wanneer parameters die door de waarde worden doorgegeven, opnieuw worden toegewezen:

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

In het voorgaande voorbeeld ziet u dat wanneer u een parameter opnieuw toewijst aan een nieuwe waarde, die wijziging niet zichtbaar is vanuit de aanroepmethode, ongeacht of het type een waardetype of een verwijzingstype is. In het volgende voorbeeld ziet u het gedrag wanneer u een parameter opnieuw toewijst die door verwijzing is doorgegeven.

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

In het voorgaande voorbeeld ziet u hoe het opnieuw toewijzen van de waarde van een parameter die doorverwijzing wordt doorgegeven, zichtbaar is in de aanroepende context.

Veilige context van verwijzingen en waarden

Methoden kunnen de waarden van parameters opslaan in velden. Wanneer parameters worden doorgegeven door een waarde, is dat meestal veilig. Waarden worden gekopieerd en referentietypen zijn bereikbaar wanneer ze zijn opgeslagen in een veld. Als u parameters op basis van verwijzing op een veilige manier doorgeeft, moet de compiler definiëren wanneer het veilig is om een verwijzing naar een nieuwe variabele toe te wijzen. Voor elke expressie definieert de compiler een veilige context die de toegang tot een expressie of variabele begrenst. De compiler maakt gebruik van twee bereiken: veilige context en ref-safe-context.

  • De veilige context definieert het bereik waar elke expressie veilig kan worden geopend.
  • De ref-safe-context definieert het bereik waar een verwijzing naar een expressie veilig kan worden geopend of gewijzigd.

Informeel kunt u deze bereiken beschouwen als het mechanisme om ervoor te zorgen dat uw code nooit toegang krijgt tot of een verwijzing wijzigt die niet langer geldig is. Een verwijzing is geldig zolang deze verwijst naar een geldig object of een geldige struct. De veilige context bepaalt wanneer een variabele kan worden toegewezen of opnieuw kan worden toegewezen. De ref-safe-context definieert wanneer een variabele kan worden toegewezen of opnieuw kan worden toegewezen. Toewijzing wijst een variabele toe aan een nieuwe waarde; Verw-toewijzing wijst de variabele toe om te verwijzen naar een andere opslaglocatie.

Referentieparameters

U past een van de volgende modifiers toe op een parameterdeclaratie om argumenten door te geven per verwijzing in plaats van op waarde:

  • ref: Het argument moet worden geïnitialiseerd voordat u de methode aanroept. De methode kan een nieuwe waarde toewijzen aan de parameter, maar is hiervoor niet vereist.
  • out: De aanroepmethode is niet vereist om het argument te initialiseren voordat u de methode aanroept. De methode moet een waarde toewijzen aan de parameter.
  • ref readonly: Het argument moet worden geïnitialiseerd voordat u de methode aanroept. De methode kan geen nieuwe waarde toewijzen aan de parameter.
  • in: Het argument moet worden geïnitialiseerd voordat u de methode aanroept. De methode kan geen nieuwe waarde toewijzen aan de parameter. De compiler kan een tijdelijke variabele maken voor het opslaan van een kopie van het argument voor in parameters.

Een parameter die wordt doorgegeven door verwijzing is een verwijzingsvariabele. Het heeft geen eigen waarde. In plaats daarvan verwijst deze naar een andere variabele met de naam referrent. Verwijzingsvariabelen kunnen worden opnieuw toegewezen, waardoor hun referent verandert.

Leden van een klas kunnen geen handtekeningen hebben die alleen verschillen per ref, ref readonlyof inout. Er treedt een compilerfout op als het enige verschil tussen twee leden van een type is dat een van deze onderdelen een parameter heeft en de andere een ref , outof ref readonly parameter heeftin. Methoden kunnen echter worden overbelast wanneer een methode een ref, ref readonlyinof parameter out heeft en de andere een parameter heeft die wordt doorgegeven door een waarde, zoals wordt weergegeven in het volgende voorbeeld. In andere situaties waarin handtekeningkoppeling is vereist, zoals verbergen of overschrijven, in, ref, , ref readonlyen out die deel uitmaken van de handtekening en niet met elkaar overeenkomen.

Wanneer een parameter een van de voorgaande modifiers heeft, kan het bijbehorende argument een compatibele wijzigingsfunctie hebben:

  • Een argument voor een ref parameter moet de ref wijzigingsfunctie bevatten.
  • Een argument voor een out parameter moet de out wijzigingsfunctie bevatten.
  • Een argument voor een in parameter kan eventueel de in wijzigingsfunctie bevatten. Als de ref wijzigingsfunctie wordt gebruikt voor het argument, geeft de compiler een waarschuwing.
  • Een argument voor een ref readonly parameter moet de in of ref modifiers bevatten, maar niet beide. Als geen van beide modifier is opgenomen, geeft de compiler een waarschuwing.

Wanneer u deze modifiers gebruikt, beschrijven ze hoe het argument wordt gebruikt:

  • ref betekent dat de methode de waarde van het argument kan lezen of schrijven.
  • out betekent dat de methode de waarde van het argument instelt.
  • ref readonly betekent dat de methode wordt gelezen, maar de waarde van het argument niet kan worden geschreven. Het argument moet worden doorgegeven met verwijzing.
  • in betekent dat de methode wordt gelezen, maar de waarde van het argument niet kan worden geschreven. Het argument wordt doorgegeven via een verwijzing of via een tijdelijke variabele.

U kunt de vorige parameteraanpassingen niet gebruiken in de volgende soorten methoden:

  • Asynchrone methoden, die u definieert met behulp van de asynchrone wijziging.
  • Iterator-methoden, waaronder een rendements- of yield break instructie.

Extensiemethoden hebben ook beperkingen voor het gebruik van deze argumenttrefwoorden:

  • Het out trefwoord kan niet worden gebruikt voor het eerste argument van een extensiemethode.
  • Het ref trefwoord kan niet worden gebruikt voor het eerste argument van een extensiemethode als het argument geen struct, of een algemeen type niet beperkt is om een struct te zijn.
  • De ref readonly trefwoorden en in trefwoorden kunnen alleen worden gebruikt als het eerste argument een struct.
  • De ref readonly trefwoorden en in trefwoorden kunnen niet worden gebruikt voor een algemeen type, zelfs niet als ze beperkt zijn tot een struct.

Eigenschappen zijn geen variabelen. Het zijn methoden. Eigenschappen kunnen geen argumenten zijn voor ref parameters.

ref parameteraanpassing

Als u een ref parameter wilt gebruiken, moeten zowel de methodedefinitie als de aanroepende methode expliciet het ref trefwoord gebruiken, zoals wordt weergegeven in het volgende voorbeeld. (Behalve dat de aanroepmethode kan weglaten ref bij het maken van een COM-aanroep.)

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

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

Een argument dat wordt doorgegeven aan een ref parameter, moet worden geïnitialiseerd voordat deze wordt doorgegeven.

out parameteraanpassing

Als u een out parameter wilt gebruiken, moeten zowel de methodedefinitie als de aanroepmethode expliciet het out trefwoord gebruiken. Voorbeeld:

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

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

Variabelen die als out argumenten worden doorgegeven, hoeven niet te worden geïnitialiseerd voordat ze worden doorgegeven in een methode-aanroep. De aangeroepen methode is echter vereist om een waarde toe te wijzen voordat de methode wordt geretourneerd.

Deconstruct-methoden declareren hun parameters met de out modifier om meerdere waarden te retourneren. Andere methoden kunnen waarde-tuples retourneren voor meerdere retourwaarden.

U kunt een variabele declareren in een afzonderlijke instructie voordat u deze als argument out doorgeeft. U kunt de out variabele ook declareren in de argumentenlijst van de methodeaanroep in plaats van in een afzonderlijke variabeledeclaratie. out variabeledeclaraties produceren compactere, leesbare code en voorkomen ook dat u per ongeluk een waarde aan de variabele toewijst vóór de methodeaanroep. In het volgende voorbeeld wordt de number variabele in de aanroep naar de methode Int32.TryParse gedefinieerd.

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

U kunt ook een impliciet getypte lokale variabele declareren.

ref readonly Modifier

De ref readonly modifier moet aanwezig zijn in de methodedeclaratie. Een wijzigingsfunctie op de oproepsite is optioneel. in De of ref modifier kan worden gebruikt. De ref readonly wijzigingsfunctie is niet geldig op de oproepsite. Welke wijzigingsfunctie u op de oproepsite gebruikt, kan helpen bij het beschrijven van kenmerken van het argument. U kunt alleen gebruiken ref als het argument een variabele is en beschrijfbaar is. U kunt het argument alleen gebruiken in als het argument een variabele is. Het kan beschrijfbaar of alleen-lezen zijn. U kunt geen van beide wijzigingsaanpassingen toevoegen als het argument geen variabele is, maar een expressie is. In de volgende voorbeelden ziet u deze voorwaarden. De volgende methode maakt gebruik van de ref readonly modifier om aan te geven dat een grote struct moet worden doorgegeven door verwijzing om prestatieredenen:

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

U kunt de methode aanroepen met behulp van de ref of in modifier. Als u de wijzigingsfunctie weglaat, geeft de compiler een waarschuwing. Wanneer het argument een expressie is, geen variabele, kunt u de in of ref modifiers niet toevoegen, dus moet u de waarschuwing onderdrukken:

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

Als de variabele een readonly variabele is, moet u de in wijzigingsfunctie gebruiken. De compiler geeft een fout op als u in plaats daarvan de ref wijzigingsfunctie gebruikt.

De ref readonly wijzigingsfunctie geeft aan dat de methode verwacht dat het argument een variabele is in plaats van een expressie die geen variabele is. Voorbeelden van expressies die geen variabelen zijn, zijn constanten, retourwaarden van methoden en eigenschappen. Als het argument geen variabele is, geeft de compiler een waarschuwing.

in parameteraanpassing

De in wijzigingsfunctie is vereist in de methodedeclaratie, maar is niet nodig op de oproepsite.

int readonlyArgument = 44;
InArgExample(readonlyArgument);
Console.WriteLine(readonlyArgument);     // value is still 44

void InArgExample(in int number)
{
    // Uncomment the following line to see error CS8331
    //number = 19;
}

Met de in wijzigingsfunctie kan de compiler een tijdelijke variabele voor het argument maken en een alleen-lezen verwijzing naar dat argument doorgeven. De compiler maakt altijd een tijdelijke variabele wanneer het argument moet worden geconverteerd, wanneer er een impliciete conversie van het argumenttype is of wanneer het argument een waarde is die geen variabele is. Als het argument bijvoorbeeld een letterlijke waarde is of de waarde die wordt geretourneerd door een eigenschapstoegangsfunctie. Wanneer uw API vereist dat het argument wordt doorgegeven via verwijzing, kiest u de ref readonly wijzigingsfunctie in plaats van de in wijzigingsfunctie.

Methoden die zijn gedefinieerd met behulp van in parameters kunnen prestatieoptimalisatie opleveren. Sommige struct typeargumenten kunnen groot zijn en wanneer methoden worden aangeroepen in strakke lussen of kritieke codepaden, zijn de kosten voor het kopiëren van deze structuren aanzienlijk. Methoden declareren in parameters om op te geven dat argumenten veilig kunnen worden doorgegeven door verwijzing, omdat de aangeroepen methode de status van dat argument niet wijzigt. Het doorgeven van deze argumenten per verwijzing voorkomt de (mogelijk) dure kopie. U voegt de in wijzigingsfunctie expliciet toe op de aanroepsite om ervoor te zorgen dat het argument wordt doorgegeven via verwijzing, niet op waarde. Expliciet gebruiken heeft in de volgende twee effecten:

  • in Als u op de aanroepsite opgeeft, moet de compiler een methode selecteren die is gedefinieerd met een overeenkomende in parameter. Als er anders slechts twee methoden aanwezig zijn in, is de by-waarde-overbelasting een betere overeenkomst.
  • Door op inte geven, declareert u uw intentie om een argument door te geven op basis van verwijzing. Het argument waarmee in wordt gebruikt, moet een locatie vertegenwoordigen waarnaar rechtstreeks kan worden verwezen. Dezelfde algemene regels voor out en ref argumenten zijn van toepassing: u kunt geen constanten, gewone eigenschappen of andere expressies gebruiken die waarden produceren. Als u anders weglaat in op de aanroepsite, wordt de compiler geïnformeerd dat het prima is om een tijdelijke variabele te maken om alleen-lezenverwijzing naar de methode door te geven. De compiler maakt een tijdelijke variabele om verschillende beperkingen met in argumenten te overwinnen:
    • Met een tijdelijke variabele kunt u tijdconstanten compileren als in parameters.
    • Een tijdelijke variabele staat eigenschappen of andere expressies voor in parameters toe.
    • Een tijdelijke variabele staat argumenten toe waarbij er een impliciete conversie van het argumenttype naar het parametertype is.

In alle voorgaande exemplaren maakt de compiler een tijdelijke variabele waarin de waarde van de constante, eigenschap of andere expressie wordt opgeslagen.

De volgende code illustreert deze regels:

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`

Stel nu dat er een andere methode beschikbaar was met behulp van argumenten voor waarden. De resultaten worden gewijzigd, zoals wordt weergegeven in de volgende code:

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`

De enige methode-aanroep waarbij het argument wordt doorgegeven door verwijzing, is de laatste.

Notitie

De voorgaande code gebruikt int als argumenttype voor eenvoud. Omdat int dit niet groter is dan een verwijzing in de meeste moderne machines, is het niet handig om één int verwijzing als een alleen-lezen verwijzing door te geven.

params Modifier

Er zijn geen andere parameters toegestaan na het params trefwoord in een methodedeclaratie en slechts één params trefwoord is toegestaan in een methodedeclaratie.

Het gedeclareerde type van de params parameter moet een verzamelingstype zijn. Herkende verzamelingstypen zijn:

Vóór C# 13 moet de parameter één dimensionale matrix zijn.

Wanneer u een methode aanroept met een params parameter, kunt u het volgende doorgeven:

  • Een door komma's gescheiden lijst met argumenten van het type matrixelementen.
  • Een verzameling argumenten van het opgegeven type.
  • Geen argumenten. Als u geen argumenten verzendt, is de lengte van de params lijst nul.

In het volgende voorbeeld ziet u verschillende manieren waarop argumenten naar een params parameter kunnen worden verzonden.

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[]
*/

Overbelastingsresolutie kan dubbelzinnigheid veroorzaken wanneer het argument voor een params parameter een verzamelingstype is. Het verzamelingstype van het argument moet worden omgezet in het verzamelingstype van de parameter. Wanneer verschillende overbelastingen betere conversies bieden voor die parameter, is die methode mogelijk beter. Als het argument voor de params parameter echter discrete elementen bevat of ontbreekt, zijn alle overbelastingen met verschillende params parametertypen gelijk aan die parameter.

Zie de sectie over argumentlijsten in de C#-taalspecificatievoor meer informatie. De taalspecificatie is de definitieve bron voor de C#-syntaxis en het gebruik.