メソッドのパラメーターと修飾子
既定では、C# の引数は値渡しで関数に渡されます。 つまり、変数のコピーがメソッドに渡されます。 値 (struct
) の型の場合、値のコピーがメソッドに渡されます。 参照 (class
) 型の場合、参照のコピーがメソッドに渡されます。 パラメーター修飾子を使用すると、引数を参照渡しできます。
構造体は
クラス インスタンスは、値の型ではなく、参照型です。 参照型がメソッドに値渡しされると、メソッドはインスタンスへの参照のコピーを受け取ります。 どちらの変数も同じオブジェクトを参照します。 パラメーターは参照のコピーです。 呼び出されたメソッドは、呼び出し元メソッド内のインスタンスを再割り当てできません。 ただし、呼び出されたメソッドは、参照のコピーを使用してインスタンス メンバーにアクセスできます。 呼び出されたメソッドがインスタンス メンバーを変更した場合、呼び出し元メソッドは、同じインスタンスを参照しているため、それらの変更を認識します。
値渡しと参照渡し
このセクションのすべての例では、次の 2 つの record
型を使用して、class
型と struct
型の違いを示します。
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; }
}
次の例の出力は、構造体型を値で渡すことと、クラス型を値で渡すことの違いを示しています。 どちらの Mutate
メソッドも、引数のプロパティ値を変更します。 パラメーターが struct
型の場合、これらの変更は引数のデータのコピーに対して行われます。 パラメーターが class
型の場合、これらの変更は引数によって参照されるインスタンスに対して行われます。
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 }
}
}
struct
型に加えられた変更は、構造体が参照によって渡されるときに呼び出し元のメソッドに表示されます。 参照型が参照によって渡される場合、セマンティックな変更はありません。
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 }
}
}
前の例では、パラメーターのプロパティを変更しました。 メソッドは、パラメーターを新しい値に再割り当てすることもできます。 再割り当ては、値または参照によって渡される場合、構造体型とクラス型で動作が異なります。 次の例は、値渡しされるパラメーターが再割り当てされるときに構造体型とクラス型がどのように動作するかを示しています。
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 }
}
}
前のサンプルは、パラメーターを新しい値に再割り当てするときに、その型が値型か参照型かに関係なく、呼び出し元のメソッドからその変更が表示されていないことを示しています。 次の例は、参照渡しされたパラメーターを再割り当てするときの動作を示しています。
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 }
}
}
前の例は、参照によって渡されるパラメーターの値を再割り当てする方法を、呼び出し元のコンテキストで表示する方法を示しています。
参照と値のセーフ コンテキスト
メソッドでは、パラメーターの値をフィールドに格納できます。 パラメーターが値渡しで渡される場合は、通常は安全です。 値がコピーされ、フィールドに格納された場合に参照型にアクセスできます。 パラメーターを参照渡しで安全に渡すには、コンパイラが新しい変数に参照を安全に代入するタイミングを定義する必要があります。 すべての式について、コンパイラは式または変数へのアクセスを制限する "セーフ コンテキスト" を定義します。 コンパイラは、safe-context と ref-safe-context という 2 つのスコープを使用します。
- safe-context は、任意の式に安全にアクセスできるスコープを定義します。
- ref-safe-context は、任意の式への "参照" に安全にアクセスしたり、変更したりできるスコープを定義します。
一般にこれらのスコープは、有効ではなくなった参照にコードがアクセスしたり、変更したりしないようにするためのメカニズムと考えることができます。 ある参照は、有効なオブジェクトまたは構造体を参照している限り有効です。 safe-context は、変数を代入または再代入できるタイミングを定義します。 ref-safe-context は、変数を ref 代入または ref 再代入できるタイミングを定義します。 代入により、変数が新しい値に割り当てられます。"ref 代入" では、変数を割り当てて別のストレージの場所を "参照" します。
参照パラメーター
パラメーター宣言に次のいずれかの修飾子を適用して、値渡しではなく参照渡しで引数を渡します。
ref
: 引数は、メソッドを呼び出す前に初期化する必要があります。 メソッドはパラメーターに新しい値を割り当てることができますが、そうする必要はありません。out
: 呼び出し元メソッドは、メソッドを呼び出す前に引数を初期化する必要はありません。 メソッドはパラメーターに値を割り当てる必要があります。ref readonly
: 引数は、メソッドを呼び出す前に初期化する必要があります。 メソッドはパラメーターに新しい値を割り当てることはできません。in
: 引数は、メソッドを呼び出す前に初期化する必要があります。 メソッドはパラメーターに新しい値を割り当てることはできません。 コンパイラは、in
パラメーターへの引数のコピーを保持するための一時変数を作成する場合があります。
参照渡しのパラメーターは、参照変数です。 独自の値はありません。 代わりに、参照と呼ばれる別の変数を参照します。 参照変数は、再割り当てすることでその参照先を変更することができます。
クラスのメンバーは、ref
、ref readonly
、in
、out
のみが異なるシグネチャを持つことはできません。 1 つの型の 2 つのメンバー間の唯一の違いが、1 つには ref
パラメーターが存在し、もう 1 つには out
、ref readonly
、in
パラメーターが存在することである場合、コンパイラ エラーが発生します。 ただし、次の例に示すように、1 つのメソッドに ref
、ref readonly
、in
、out
パラメーターがあり、もう 1 つには値渡しされるパラメーターがある場合、メソッドをオーバーロードすることができます。 非表示やオーバーライドなど、シグネチャの一致が必要な他の状況では、in
、ref
、ref readonly
、out
はシグネチャの一部であり、互いに一致しません。
パラメーターに前述のいずれかの修飾子がある場合、対応する引数には互換性のある修飾子を指定できます。
ref
パラメーターの引数には、ref
修飾子を含める必要があります。out
パラメーターの引数には、out
修飾子を含める必要があります。in
パラメーターの引数には、必要に応じてin
修飾子を含めることができます。 代わりにその引数でref
修飾子が使用されている場合、コンパイラは警告を出します。ref readonly
パラメーターの引数には、in
修飾子またはref
修飾子を含める必要がありますが、両方を含める必要はありません。 どちらの修飾子も含まれていない場合、コンパイラは警告を出します。
これらの修飾子を使用すると、次のように引数の使用方法が説明されます。
ref
は、メソッドが引数の値を読み取ったり書き込んだりできることを意味します。out
は、メソッドが引数の値を設定することを意味します。ref readonly
は、メソッドが引数の値を読み取りますが、書き込めないことを意味します。 引数は参照渡しで渡す必要があります。in
は、メソッドが引数の値を読み取りますが、書き込めないことを意味します。 引数は、参照渡しまたは一時変数を介して渡されます。
次の種類のメソッドでは、前述のパラメーター修飾子を使用できません。
- async 修飾子を使用して定義した Async メソッド。
- yield return または
yield break
ステートメントを含む Iterator メソッド。
拡張メソッドには、これらの引数キーワードの使用に関する制限もあります。
- 拡張メソッドの最初の引数では、
out
キーワードを使用できません。 - 引数が
ref
でない場合、または構造体として制約されていないジェネリック型の場合、拡張メソッドの最初の引数でstruct
キーワードを使用することはできません。 - 最初の引数が
ref readonly
である場合を除き、in
およびstruct
キーワードは使用できません。 - ジェネリック型では、構造体として制約されている場合であっても、
ref readonly
およびin
キーワードを使用することはできません。
プロパティは変数ではありません。 これらはメソッドです。 プロパティは、ref
パラメーターの引数にすることはできません。
ref
パラメーター修飾子
ref
パラメーターを使用するには、メソッド定義と呼び出し元のメソッドの両方が、次の例に示すように ref
キーワードを明示的に使用する必要があります。 (例外として、COM 呼び出しを行う場合は、呼び出し元のメソッドで ref
を省略できます)。
void Method(ref int refArgument)
{
refArgument = refArgument + 44;
}
int number = 1;
Method(ref number);
Console.WriteLine(number);
// Output: 45
ref
パラメーターに渡す引数は、渡す前に初期化する必要があります。
out
パラメーター修飾子
out
パラメーターを使用するには、メソッド定義と呼び出し元のメソッドの両方で out
キーワードを明示的に使用する必要があります。 次に例を示します。
int initializeInMethod;
OutArgExample(out initializeInMethod);
Console.WriteLine(initializeInMethod); // value is now 44
void OutArgExample(out int number)
{
number = 44;
}
out
の引数として渡される変数は、メソッド呼び出しで渡される前に初期化する必要はありません。 ただし、呼び出されたメソッドでは、メソッドから制御が返される前に値を割り当てる必要があります。
Deconstruct メソッドは、複数の値を返すために、out
修飾子を使用してパラメーターを宣言します。 他のメソッドは、複数の戻り値の値タプルを返すことができます。
変数を別のステートメントで宣言してから、out
引数として渡すことができます。 out
変数を、別の変数宣言内ではなく、メソッド呼び出しの引数リスト内で宣言することもできます。 out
変数宣言により、よりコンパクトで読みやすいコードが生成されます。また、メソッド呼び出しの前に誤って変数に値を割り当てることもなくなります。 次の例は、number
メソッドの呼び出しで 変数を定義しています。
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
暗黙的に型指定されたローカル変数を宣言することもできます。
ref readonly
modifier
ref readonly
修飾子は、メソッド宣言に存在する必要があります。 呼び出しサイトの修飾子は省略可能です。 in
または ref
修飾子を使用できます。 ref readonly
修飾子は、呼び出しサイトでは無効です。 呼び出しサイトで使用する修飾子は、引数の特性を記述するのに役立ちます。 引数が変数であり、書き込み可能な場合にのみ、ref
を使用できます。 引数が変数の場合にのみ in
を使用できます。 書き込み可能な場合もあれば、読み取り専用の場合もあります。 引数が変数ではなく式である場合は、どちらの修飾子も追加できません。 次の例は、これらの条件を示しています。 次のメソッドでは、ref readonly
修飾子を使用して、パフォーマンス上の理由から、大きな構造体を参照渡しする必要があることを示しています。
public static void ForceByRef(ref readonly OptionStruct thing)
{
// elided
}
ref
または in
修飾子を使用してメソッドを呼び出すことができます。 修飾子を省略すると、コンパイラは警告を出します。 引数が変数ではなく式の場合は、in
または ref
修飾子を追加できないため、警告を抑制する必要があります。
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
変数が readonly
変数の場合は、in
修飾子を使用する必要があります。 代わりに ref
修飾子を使用すると、コンパイラはエラーを出します。
ref readonly
修飾子は、引数が変数ではない式ではなく、変数であるとメソッドは想定している、ということを示します。 変数ではない式の例としては、定数、メソッドの戻り値、プロパティがあります。 引数が変数でない場合、コンパイラは警告を出します。
in
パラメーター修飾子
メソッド宣言では in
修飾子が必要ですが、呼び出しサイトでは不要です。
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;
}
in
修飾子を使用すると、コンパイラは引数の一時変数を作成し、その引数への読み取り専用参照を渡すことができます。 コンパイラは、引数を変換する必要がある場合、引数の型から暗黙的な変換がある場合、または引数が変数ではない値である場合は、常に一時変数を作成します。 たとえば、引数がリテラル値の場合や、プロパティ アクセサーから返される値の場合です。 API で引数を参照渡しする必要がある場合は、ref readonly
修飾子ではなく in
修飾子を選択します。
in
パラメーターを使用して定義されたメソッドには、パフォーマンスを最適化できる可能性があります。 一部の struct
型引数は、サイズが大きくなる可能性があり、メソッドが短いループまたは重要なコード パスで呼び出される場合、その構造のコピーのコストが大きくなります。 呼び出されたメソッドは引数の状態を変更しないため、メソッドで in
パラメーターを宣言して、参照渡しで安全に渡すことができる引数を指定します。 参照によりこれらの引数を渡して、(可能性がある) 高額なコピーを回避します。 呼び出しサイトで in
修飾子を明示的に追加して、引数が値ではなく、参照で渡されるようにします。 明示的に in
を使用すると、次の 2 つの効果があります。
- 呼び出しサイトで
in
を指定すると、コンパイラは、一致するin
パラメーターで定義されたメソッドを強制的に選択します。 それ以外の場合は、2 つのメソッドでin
の有無のみが異なるときは、値によるオーバーロードの方が適しています。 in
を指定することで、参照渡しで引数を渡す意図を宣言します。in
で使用される引数では、直接参照できる場所を表す必要があります。out
およびref
引数と同じ一般ルールが適用されます。定数、通常のプロパティ、または値を生成するその他の式を使用することはできません。 それ以外の場合は、呼び出しサイトでin
を省略すると、メソッドに読み取り専用の参照渡しで渡すために、一時変数を作成しても問題ないことが、コンパイラに通知されます。 コンパイラでは、一時変数を作成して、in
引数でのいくつかの制限に対処します。- 一時変数では、
in
パラメーターとしてコンパイル時の定数を許可します。 - 一時変数では、プロパティ、または
in
パラメーターのその他の式を許可します。 - 一時変数では、引数の型からパラメーターの型への暗黙の変換がある引数を許可します。
- 一時変数では、
先のすべてのインスタンスで、コンパイラは定数、プロパティ、またはその他の式の値を格納する一時変数を作成します。
これらのルールが発生するコード例を次に示します。
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`
ここでは、値渡しの引数を使用する別のメソッドが使用できたと想定します。 次のコードに示すように、結果が変更されます。
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`
引数が参照で渡されるメソッドの呼び出しは、最後のメソッドのみです。
注意
先のコードでは、わかりやすくするために int
を引数型として使用します。 int
は最新のマシンの参照より大きくなることはないため、読み取り専用の参照として単一の int
を渡すメリットはありません。
params
modifier
1 つのメソッド宣言内では、params
キーワード以後に他のパラメーターを使用できず、1 つの params
キーワードだけを使用できます。
params
パラメーターの宣言される型は、コレクション型である必要があります。 認識されるコレクション型は次のとおりです。
- 1 次元の "配列型" 。この場合、"要素型" は
T[]
です。T
- "スパン型":
System.Span<T>
System.ReadOnlySpan<T>
ここで、"要素型" は です。T
- 対応する "要素型" でアクセス可能な "作成メソッド" を持つ "型"。 "作成メソッド" は、コレクション式に使われるのと同じ属性を使って識別されます。
- 次のような、 を実装する "構造体" または "クラス型":System.Collections.Generic.IEnumerable<T>
- "型" には引数なしで呼び出すことができるコンストラクターがあり、コンストラクターは少なくとも宣言しているメンバーと同程度にアクセス可能です。
- "!型" には、次のようなインスタンス (拡張ではない) メソッド があります。
Add
- メソッドは、単一の値引数で呼び出すことができます。
- メソッドがジェネリックの場合、型引数は引数から推論できます。
- メソッドは、少なくとも宣言しているメンバーと同程度にアクセス可能です。 ここで、"要素型" は "型" の "反復型" です。
- "インターフェイス型":
C# 13 より前のパラメーターは、1 次元配列である必要があります。
params
パラメーターを使用してメソッドを呼び出す場合は、以下を渡すことができます。
- 配列要素の型の引数のコンマ区切りのリスト。
- 指定した型の引数のコレクション。
- 引数なし。 引数を渡さない場合、
params
リストの長さはゼロになります。
次の例に示すように、さまざまな方法で params
パラメーターに引数を渡すことができます。
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[]
*/
オーバーロードの解決により、 params
パラメーターの引数がコレクション型である場合、あいまいさが発生する可能性があります。 引数のコレクション型は、パラメーターのコレクション型に変換できる必要があります。 異なるオーバーロードによってそのパラメーターの変換が向上する場合、そのメソッドの方が適している可能性があります。 ただし、 params
パラメーターの引数が不連続要素または不足している場合、 params
パラメーター型が異なるすべてのオーバーロードは、そのパラメーターに対して等しくなります。
詳細については、「
.NET