Jegyzet
Az oldalhoz való hozzáférés engedélyezést igényel. Próbálhatod be jelentkezni vagy könyvtárat váltani.
Az oldalhoz való hozzáférés engedélyezést igényel. Megpróbálhatod a könyvtár váltását.
A C# alapértelmezés szerint érték szerint adja át az argumentumokat a függvényeknek. Ez a módszer átadja a változó másolatát a metódusnak. Értéktípusokstruct esetén a metódus másolatot kap az értékről. Hivatkozási (class) típusok esetén a metódus másolatot kap a hivatkozásról. Paramétermódosítókkal hivatkozva adhat át argumentumokat.
Mivel a struktúra értéktípus, a metódusnak átadott struktúra az argumentum másolatát küldi el a metódusnak. A metódus ezzel a másolattal működik. A metódus nem tudja elérni a hívási metódus eredeti szerkezetét, és nem tudja módosítani. A metódus csak a másolatot módosíthatja.
Az osztálypéldányok hivatkozási típusok, nem értéktípusok. Amikor egy hivatkozástípust érték szerint ad át egy metódusnak, a metódus másolatot kap a példányra mutató hivatkozásról. Mindkét változó ugyanarra az objektumra hivatkozik. A paraméter a hivatkozás másolata. A hívott metódus nem tudja újból hozzárendelni a példányt a hívó metódusban. A hívott metódus azonban a hivatkozás másolatát használhatja a példánytagok eléréséhez. Ha a hívott metódus módosít egy példánytagot, a hívó metódus is látja ezeket a változásokat, mivel ugyanarra a példányra hivatkozik.
A C# nyelv referenciadokumentuma a C# nyelv legújabb kiadású verzióját ismerteti. Emellett a közelgő nyelvi kiadás nyilvános előzetes verziójú funkcióinak kezdeti dokumentációját is tartalmazza.
A dokumentáció azonosítja azokat a funkciókat, amelyeket először a nyelv utolsó három verziójában vagy az aktuális nyilvános előzetes verziókban vezetnek be.
Jótanács
Ha meg szeretné tudni, hogy mikor jelent meg először egy funkció a C#-ban, tekintse meg a C# nyelvi verzióelőzményeiről szóló cikket.
Pass by value and pass by reference
A jelen szakaszban szereplő összes példa a következő két record típust használja a típusok és class a típusok közötti struct különbségek szemléltetésére:
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; }
}
Az alábbi példa kimenete azt a különbséget mutatja be, hogy a szerkezettípus érték szerint való átadása és egy osztálytípus érték szerinti átadása között van-e különbség. Mindkét Mutate metódus módosítja az argumentumuk tulajdonságértékeit. Ha a paraméter típus struct , ezek a módosítások hatással vannak az argumentum adatainak másolatára. Ha a paraméter típus class , ezek a változások az argumentum által hivatkozott példányt érintik:
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 }
}
}
A ref módosító az argumentumok metódusokra való hivatkozással történő átadásának egyik módja. Az alábbi kód replikálja az előző példát, de hivatkozással adja át a paramétereket. A típus módosításai struct a hívó metódusban láthatók, amikor a szerkezetet hivatkozással továbbítja. Nincs szemantikai változás, ha egy referenciatípust hivatkozással ad át:
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 }
}
}
Az előző példák egy paraméter módosított tulajdonságait mutatták be. A metódusok egy paramétert egy új értékhez is hozzárendelhetnek. Az újra-hozzárendelés másként viselkedik a struktúra és az osztálytípusok esetében, ha érték vagy hivatkozás alapján ad át. Az alábbi példa bemutatja, hogyan viselkednek a szerkezettípusok és az osztálytípusok az érték által átadott paraméterek újbóli hozzárendelésekor:
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 }
}
}
Az előző minta azt mutatja, hogy amikor egy paramétert egy új értékhez rendel hozzá, az a változás nem látható a hívási módszerből, függetlenül attól, hogy a típus értéktípus vagy referenciatípus. Az alábbi példa azt a viselkedést mutatja be, amikor újra hozzárendel egy paramétert, amelyet a metódus a hivatkozással kapott:
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 }
}
}
Az előző példa bemutatja, hogyan jelenik meg egy hivatkozás által átadott paraméter értékének újbóli hozzárendelése a hívási környezetben.
Hivatkozások és értékek biztonságos környezete
A metódusok a paraméterek értékeit mezőkben tárolhatják. Ha érték szerint ad át paramétereket, az általában biztonságos. A metódus átmásolja az értékeket, és a referenciatípusok akkor érhetők el, ha a metódus egy mezőben tárolja őket. A paraméterek biztonságos hivatkozással történő átadásához a fordítónak meg kell határoznia, hogy mikor lehet biztonságosan hozzárendelni egy hivatkozást egy új változóhoz. A fordító minden kifejezéshez meghatároz egy olyan biztonságos környezetet , amely egy kifejezéshez vagy változóhoz való hozzáférést köti. A fordító két hatókört használ: safe-context és ref-safe-context.
- A biztonságos környezet határozza meg azt a hatókört, amelyben bármely kifejezés biztonságosan elérhető.
- A ref-safe-context határozza meg azt a hatókört , amelyben bármely kifejezésre mutató hivatkozás biztonságosan elérhető vagy módosítható.
Informálisan úgy tekinthet ezekre a hatókörökre, mint a mechanizmusra, amely biztosítja, hogy a kód soha ne férhessen hozzá vagy módosítson egy már nem érvényes hivatkozást. A hivatkozás mindaddig érvényes, amíg érvényes objektumra vagy szerkezetre hivatkozik. A biztonságos környezet határozza meg, hogy mikor rendelhető hozzá vagy rendelhető hozzá újra egy változó. A ref-safe-context azt határozza meg, hogy mikor rendelhető hozzá újra egy változó, vagy mikor lehet újból hozzárendelni. A hozzárendelés egy változót rendel egy új értékhez; A ref-hozzárendelés hozzárendeli a változót egy másik tárolóhelyre való hivatkozáshoz.
Referenciaparaméterek
Ha az argumentumokat hivatkozással szeretné átadni érték helyett, használja az alábbi módosítók egyikét egy paraméterdeklarációban:
-
ref: Inicializálja az argumentumot a metódus meghívása előtt. A metódus új értéket rendelhet a paraméterhez, de nem szükséges. -
out: A hívó metódusnak nem kell inicializálnia az argumentumot a metódus meghívása előtt. A metódusnak hozzá kell rendelnie egy értéket a paraméterhez. -
ref readonly: Inicializálja az argumentumot a metódus meghívása előtt. A metódus nem tud új értéket hozzárendelni a paraméterhez. -
in: Inicializálja az argumentumot a metódus meghívása előtt. A metódus nem tud új értéket hozzárendelni a paraméterhez. A fordító létrehozhat egy ideiglenes változót, amely az argumentum egy másolatát tárolja a paramétereknekin.
A hivatkozás által átadott paraméter egy referenciaváltozó. Nincs saját értéke. Ehelyett egy másik, hivatkozásnak nevezett változóra hivatkozik. Újra hozzárendelheti a referenciaváltozókat, amelyek módosítják a hivatkozásukat.
Az osztály tagjai nem rendelkezhetnek olyan aláírásokkal, amelyek csak az ref, , ref readonlyinvagy out. Fordítóhiba akkor fordul elő, ha egy típus két tagja között az egyetlen különbség az, hogy az egyik tag rendelkezik paraméterrel ref , a másik tag pedig egy out, ref readonlyvagy in paraméterrel. Azonban túlterhelheti a metódusokat, ha az egyik metódus rendelkezik refegy , ref readonly, invagy out paraméterrel, a másik metódus pedig egy érték által átadott paraméterrel, ahogyan az az alábbi példában látható. Más olyan helyzetekben, amelyekhez aláírás-egyeztetés szükséges, például elrejtés vagy felülbírálás, inrefref readonlyaz out aláírás részét képezik, és nem egyeznek egymással.
Ha egy paraméter rendelkezik az előző módosítók egyikével, a megfelelő argumentum kompatibilis módosítóval rendelkezhet:
- Egy paraméter argumentumának
reftartalmaznia kell a módosító értékétref. - Egy paraméter argumentumának
outtartalmaznia kell aoutmódosító értékét. - Egy paraméter argumentuma
inopcionálisan tartalmazhatja ainmódosító értékét. Ha arefmódosító helyett az argumentumot használja, a fordító figyelmeztetést ad ki. - Egy paraméter argumentumának
ref readonlytartalmaznia kell a módosítókat vagyinarefmódosítókat, de mindkettőt nem. Ha egyik módosító sem szerepel a fájlban, a fordító figyelmeztetést ad ki.
Ha ezeket a módosítókat használja, az argumentum használatának módját írják le:
-
refazt jelenti, hogy a metódus képes az argumentum értékének olvasására vagy írására. -
outazt jelenti, hogy a metódus beállítja az argumentum értékét. -
ref readonlyazt jelenti, hogy a metódus beolvassa, de nem tudja megírni az argumentum értékét. Az argumentumot hivatkozással kell átadni. -
inazt jelenti, hogy a metódus beolvassa, de nem tudja megírni az argumentum értékét. Az argumentumot hivatkozás vagy ideiglenes változó adja át.
Az előző paramétermódosítókat nem használhatja a következő metódustípusokban:
- Aszinkron metódusok, amelyeket az aszinkron módosító használatával határoz meg.
- Iterátormetódusok, amelyek hozamhozamottartalmaznak.
A bővítménytagok az alábbi argumentumszavak használatára is korlátozásokkal rendelkeznek:
- A
outkulcsszó nem használható a bővítménymetódus első argumentumán. - A
refkulcsszó nem használható a bővítménymetódus első argumentumán, ha az argumentum nemstructegy , vagy egy általános típus, amely nem konstruktálásra van korlátozva. - A
ref readonlykulcsszavak ésina kulcsszavak csak akkor használhatók, ha az első argumentum egystruct. - A
ref readonlykulcsszavak ésina kulcsszavak nem használhatók általános típuson, még akkor sem, ha a szerkezetre korlátozva van.
A tulajdonságok nem változók. Ezek metódusok. Paraméterek argumentumaként ref nem használhat tulajdonságokat.
ref paramétermódosító
Paraméter ref használatához a metódusdefiníciónak és a hívási módszernek is explicit módon kell használnia a ref kulcsszót, ahogyan az az alábbi példában is látható. (Kivéve, hogy a hívási módszer kihagyhatja ref a COM-hívásokat.)
void Method(ref int refArgument)
{
refArgument = refArgument + 44;
}
int number = 1;
Method(ref number);
Console.WriteLine(number);
// Output: 45
Mielőtt átad egy paraméternek, inicializálnia kell egy argumentumot ref .
out paramétermódosító
Paraméter használatához out a metódusdefiníciónak és a hívási módszernek is explicit módon kell használnia a kulcsszót out . Példa:
int initializeInMethod;
OutArgExample(out initializeInMethod);
Console.WriteLine(initializeInMethod); // value is now 44
void OutArgExample(out int number)
{
number = 44;
}
A metódushívás előtt nem kell inicializálnia az argumentumként out átadott változókat. A hívott metódusnak azonban a visszatérés előtt hozzá kell rendelnie egy értéket.
A dekonstruálási metódusok a módosítóval deklarálják a out paramétereket, hogy több értéket adjanak vissza. Más metódusok több visszatérési értékhez is visszaadhatják az értékeket .
Egy változót külön utasításban deklarálhat, mielőtt argumentumként out ad át. A változót a out metódushívás argumentumlistájában is deklarálhatja, nem pedig külön változódeklarációban.
out a változódeklarációk tömörebb, olvashatóbb kódot eredményeznek, és megakadályozzák, hogy véletlenül értéket rendeljen a változóhoz a metódushívás előtt. Az alábbi példa az number Int32.TryParse metódus hívásában definiálja a változót.
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
Implicit módon beírt helyi változót is deklarálhat.
ref readonly módosító
A metódus deklarálásához a ref readonly módosító szükséges. A hívási helyen nem kötelező módosító. Használhatja a módosító vagy ref a in módosító. A ref readonly módosító érvénytelen a hívási helyen. A hívási helyen használt módosító segíthet az argumentum jellemzőinek leírásában. Csak akkor használható ref , ha az argumentum változó, és írható. Csak akkor használható in , ha az argumentum változó. A változó írható vagy olvasható lehet. Egyik módosító sem vehető fel, ha az argumentum nem változó, hanem kifejezés. Az alábbi példák ezeket a feltételeket mutatják be. A következő módszer a ref readonly módosító használatával jelzi, hogy egy nagy szerkezetet teljesítménybeli okokból kell átadni:
public static void ForceByRef(ref readonly OptionStruct thing)
{
// elided
}
A metódust a módosító vagy in a ref módosító használatával hívhatja meg. Ha kihagyja a módosítót, a fordító figyelmeztetést ad ki. Ha az argumentum kifejezés, nem változó, akkor nem lehet hozzáadni a módosítókat vagy in a ref módosítókat, ezért el kell kerülnie a figyelmeztetést:
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
Ha a változó változó readonly , akkor a in módosítót kell használnia. A fordító hibát ad ki, ha ehelyett a ref módosítót használja.
A ref readonly módosító azt jelzi, hogy a metódus az argumentumot nem változóként, hanem változóként várja meg. A nem változó kifejezések például állandók, metódusok visszatérési értékei és tulajdonságai. Ha az argumentum nem változó, a fordító figyelmeztetést ad ki.
in paramétermódosító
A in módosító szükséges a metódus deklarációjában, de a hívás helyszínén szükségtelen.
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;
}
A in módosító lehetővé teszi a fordító számára, hogy ideiglenes változót hozzon létre az argumentumhoz, és egy egyszerű hivatkozást adjon át az argumentumra. A fordító mindig létrehoz egy ideiglenes változót, amikor az argumentumot konvertálni kell, amikor implicit átalakítás történik az argumentumtípusból, vagy ha az argumentum nem változó érték. Ha például az argumentum egy literális érték, vagy egy tulajdonság tartozékából visszaadott érték. Ha az API megköveteli, hogy az argumentumot hivatkozással adja át, válassza a ref readonly módosító helyett a in módosítót.
A teljesítményoptimalizálást a paraméterekkel rendelkező metódusok definiálásával in érheti el. Egyes struct típusargumentumok mérete nagy lehet, és ha szoros hurkokban vagy kritikus kódelérési utakon hívja meg a metódusokat, a struktúrák másolásának költsége jelentős. Deklarálja in a paramétereket annak megadásához, hogy hivatkozással biztonságosan átadhassa az argumentumokat, mert a hívott metódus nem módosítja az argumentum állapotát. Ezeknek az argumentumoknak a hivatkozással történő átadása elkerüli a (potenciálisan) költséges másolatot. Explicit módon adja hozzá a in módosítót a hívási helyen, hogy az argumentumot hivatkozás, nem érték szerint adja át. Az explicit használatnak in két hatása van:
-
inA hívási hely megadása arra kényszeríti a fordítót, hogy válasszon ki egy egyezőinparaméterrel definiált metódust. Ellenkező esetben, ha két módszer csak jelenlétébeninkülönbözik, az érték szerinti túlterhelés jobb egyezés. - A beállítással
indeklarálja az argumentumok hivatkozással való átadására vonatkozó szándékát. A használt argumentumnakinegy közvetlenül hivatkozható helyet kell jelölnie. Ugyanezek az általános szabályokoutésrefargumentumok érvényesek: Nem használhat állandókat, szokásos tulajdonságokat vagy más értékeket termelő kifejezéseket. Ellenkező esetben a hívási helyen való kihagyásintájékoztatja a fordítót, hogy nem baj, ha egy ideiglenes változót hoz létre, amelyet csak olvasható hivatkozással adhat át a metódusnak. A fordító létrehoz egy ideiglenes változót, amely argumentumokkalinold meg számos korlátozást:- Az ideiglenes változók paraméterként
inlehetővé teszik a fordítási idő állandóit. - Az ideiglenes változók lehetővé teszik a paraméterek tulajdonságait vagy más kifejezéseit
in. - Az ideiglenes változók olyan argumentumokat engedélyeznek, ahol implicit átalakítás történt az argumentumtípusról a paramétertípusra.
- Az ideiglenes változók paraméterként
Az összes előző példányban a fordító létrehoz egy ideiglenes változót, amely az állandó, a tulajdonság vagy más kifejezés értékét tárolja.
A következő kód az alábbi szabályokat mutatja be:
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`
Tegyük fel, hogy egy másik metódus is elérhető volt értékalapú argumentumokkal. Az eredmények a következő kódban látható módon változnak:
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`
Az egyetlen metódushívás, ahol az argumentumot hivatkozással adja át, az utolsó.
Feljegyzés
Az előző kód argumentumtípusként használja int az egyszerűséget. Mivel int a legtöbb modern gépen nem nagyobb, mint egy hivatkozás, nincs előnye egyetlen egyszerű hivatkozásként való átadásnak int .
params módosító
A kulcsszóval rendelkező params paraméternek kell lennie a metódusdeklaráció utolsó paraméterének. Egy metódusdeklarációban csak egy params kulcsszó használható.
A paramétert params gyűjteménytípusként kell deklarálnia. A felismert gyűjteménytípusok a következők:
- Egydimenziós tömbtípus
T[], ahol az elem típusa.T - Egy span típus:
System.Span<T>System.ReadOnlySpan<T>
Ezekben a típusokban az elem típusa a következőT: .
- A megfelelő elemtípussal rendelkező, akadálymentes létrehozási metódussal rendelkező típus. A létrehozási módszer ugyanazt az attribútumot használja, mint a gyűjteménykifejezések.
- Olyan szerkezet vagy osztálytípus , amely az alábbiakat valósítja meg System.Collections.Generic.IEnumerable<T> :
- A típus rendelkezik egy konstruktorsal, amelyet argumentumok nélkül hívhat meg, és a konstruktor legalább olyan elérhető, mint a deklaráló tag.
- A típusnak van egy példánya (nem bővítménye),
Addahol:- A metódus egyetlen érték argumentummal hívható meg.
- Ha a metódus általános, a típusargumentumok kikövetkeztethetők az argumentumból.
- A módszer legalább olyan akadálymentes, mint a deklaráló tag. Ebben az esetben az elem típusa a típusiterációs típusa.
- Felület típusa:
- System.Collections.Generic.IEnumerable<T>
- System.Collections.Generic.IReadOnlyCollection<T>
- System.Collections.Generic.IReadOnlyList<T>
- System.Collections.Generic.ICollection<T>
-
System.Collections.Generic.IList<T> Ezekben a típusokban az elem típusa a következő
T: .
A C# 13 előtt egy egydimenziós tömböt kell használnia a paraméterhez.
Ha paraméterrel rendelkező metódust params hív meg, a következőt adhatja meg:
- A tömbelemek típusának argumentumainak vesszővel tagolt listája.
- A megadott típusú argumentumok gyűjteménye.
- Nincsenek argumentumok. Ha nem küld argumentumokat, a
paramslista hossza nulla.
Az alábbi példa azt mutatja be, hogyan küldhet argumentumokat egy params paraméternek.
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[]
*/
A túlterhelés feloldása kétértelműséget okozhat, ha egy params paraméter argumentuma gyűjteménytípus. Az argumentum gyűjteménytípusának konvertálhatónak kell lennie a paraméter gyűjteménytípusára. Ha a különböző túlterhelések jobb konverziókat biztosítanak az adott paraméterhez, ez a módszer jobb lehet. Ha azonban a params paraméter argumentuma különálló elemek vagy hiányzik, akkor a különböző params paramétertípusokkal rendelkező összes túlterhelés megegyezik az adott paraméterrel.
További információt a C# nyelvspecifikációargumentumlistáinak szakaszában talál. A nyelvi specifikáció a C#-szintaxis és -használat végleges forrása.