out パラメーター修飾子 (C# リファレンス)

out キーワードによって、参照により引数が渡されます。 仮パラメーターを引数 (変数にする必要があります) の別名にします。 つまり、パラメーターに対するすべての操作は引数に対して行われます。 これは、ref キーワードと似ていますが、ref では、変数を初期化してから渡す必要があります。 in キーワードとも似ていますが、in では、呼び出されたメソッドで引数の値を変更することはできません。 out パラメーターを使用するには、メソッド定義と呼び出し元のメソッドの両方で out キーワードを明示的に使用する必要があります。 次に例を示します。

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

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

注意

out キーワードは、ジェネリック型パラメーターと共に使用すると、型パラメーターが共変であることを指定することもできます。 このコンテキストでの out キーワードの使用方法の詳細については、「out (ジェネリック修飾子)」を参照してください。

out の引数として渡される変数は、メソッド呼び出しで渡される前に初期化する必要はありません。 ただし、呼び出されたメソッドでは、メソッドから制御が返される前に値を割り当てる必要があります。

inref、および out キーワードは、オーバーロード解決のためのメソッド シグネチャの一部とは見なされません。 したがって、唯一の違いが、1 つのメソッドは ref または in 引数を受け取り、もう一方のメソッドは out 引数を受け取ることである場合、メソッドはオーバーロードできません。 たとえば、次のコードはコンパイルされません。

class CS0663_Example
{
    // Compiler error CS0663: "Cannot define overloaded
    // methods that differ only on ref and out".
    public void SampleMethod(out int i) { }
    public void SampleMethod(ref int i) { }
}

ただし、一方のメソッドが refin、または out 引数を受け取り、もう一方のメソッドにいずれの修飾子もない場合は、オーバーロードを実行できます。この例を次に示します。

class OutOverloadExample
{
    public void SampleMethod(int i) { }
    public void SampleMethod(out int i) => i = 5;
}

コンパイラは、呼び出しサイトのパラメーター修飾子と、メソッド呼び出しで使用されるパラメーター修飾子を照合して、最適なオーバーロードを選択します。

プロパティは変数ではないため、out パラメーターとして渡すことはできません。

次の種類のメソッドには、inrefout キーワードを使用することはできません。

  • async 修飾子を使用して定義した Async メソッド。

  • yield return または yield break ステートメントを含む Iterator メソッド。

さらに、拡張メソッドには次の制約があります。

  • 拡張メソッドの最初の引数では、out キーワードを使用できません。
  • 拡張メソッドの最初の引数が構造体ではない場合、または構造体として制約されていないジェネリック型である場合、その引数で ref キーワードを使用することはできません。
  • 最初の引数が構造体である場合を除き、in キーワードは使用できません。 ジェネリック型では、構造体として制約されている場合であっても、in キーワードを使用することはできません。

out パラメーターの宣言

out 引数を含むメソッドの宣言は、複数の値を返すための従来の回避策です。 同様のシナリオでは値タプルを検討してください。 次の例では out を使用して、1 つのメソッド呼び出しで 3 つの変数を返します。 3 番目の引数が null に割り当てられます。 これにより、必要に応じてメソッドが値を返すことができます。

void Method(out int answer, out string message, out string stillNull)
{
    answer = 44;
    message = "I've been returned";
    stillNull = null;
}

int argNumber;
string argMessage, argDefault;
Method(out argNumber, out argMessage, out argDefault);
Console.WriteLine(argNumber);
Console.WriteLine(argMessage);
Console.WriteLine(argDefault == null);

// The example displays the following output:
//      44
//      I've been returned
//      True

out 引数を含むメソッドの呼び出し

変数を別のステートメントで宣言してから、out 引数として渡すことができます。 次の例では、number という名前の変数を宣言してから、文字列を数値に変換する Int32.TryParse メソッドに渡しています。

string numberAsString = "1640";

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

out 変数を、別の変数宣言内ではなく、メソッド呼び出しの引数リスト内で宣言することもできます。 これにより、よりコンパクトで読みやすいコードが生成されます。また、メソッド呼び出しの前に誤って変数に値を割り当てることもなくなります。 次の例は前の例と似ていますが、Int32.TryParse メソッドの呼び出しで 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

前の例では、number 変数は int として厳密に型指定されています。 次の例のように、暗黙的に型指定されたローカル変数を宣言することもできます。

string numberAsString = "1640";

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

C# 言語仕様

詳細については、「C# 言語の仕様」を参照してください。 言語仕様は、C# の構文と使用法に関する信頼性のある情報源です。

関連項目