私はコアC#プログラミング構造を読んでいて、out
パラメーター修飾子に頭を悩ませるのに苦労しています。私はそれが何をするかを読むことで知っていますが、私がそれを使うときのシーンリオを考えようとしています。
誰かが私に実際の例を教えてもらえますか?ありがとう。
私はコアC#プログラミング構造を読んでいて、out
パラメーター修飾子に頭を悩ませるのに苦労しています。私はそれが何をするかを読むことで知っていますが、私がそれを使うときのシーンリオを考えようとしています。
誰かが私に実際の例を教えてもらえますか?ありがとう。
パラメータを使用する主な動機out
は、関数が複数の値を呼び出し元に返すことができるようにすることであり、他のすべての人がフレームワークで例を提供しました。out
そもそもパラメータを持つことの背後にある理由を探ることによって、あなたの質問に答えるために別のアプローチを取ります。実際の例は書きませんが、説明します。
通常、値を返すメカニズムは、関数の戻り値の1つだけです。確かに、グローバル(静的)変数またはインスタンス変数を使用することもできますが、それは一般的にはあまり実用的でも安全でもありません(理由はここでは説明しません)。 .NET 3.5より前は、関数から複数の値を返す実際的な方法はありませんでした。out
または修飾子が使用できない場合ref
は、いくつかのオプションがあります。
すべての値が同じタイプである場合、値のコレクションを返すことができます。これはほとんどの場合完全に問題ありません。数値の配列、文字列のリストなどを返すことができます。すべての値がまったく同じ方法で関連している場合、これは完璧です。つまり、すべての数字はコンテナ内のアイテムの数であるか、リストはパーティーのゲストの名前でした。しかし、返された値が異なる量を表している場合はどうなるでしょうか。タイプが異なる場合はどうなりますか?オブジェクトのリストはそれらすべてを保持できますが、その種のデータを操作するための非常に直感的な方法ではありません。
異なるタイプの複数の値を返す必要がある場合、唯一の実用的なオプションは、これらすべての値をカプセル化してそのタイプのインスタンスを返す新しいクラス/構造体タイプを作成することでした。そうすることで、直感的な名前で強く型付けされた値を返すことができ、この方法で複数の値を返すことができます。問題は、それを取得するために、特定の名前で型を定義する必要があり、複数の値を返すことができるようにするためだけにすべてを定義する必要があることです。型を作成するのが実用的でないほど単純な2つの値だけを返したい場合はどうでしょうか。さらにいくつかのオプションがあります。
ジェネリック型のセットを作成して、さまざまな型(関数型言語のタプルなど)の値を一定量含めることができます。しかし、当時はフレームワークの一部ではなかったため、再利用可能な方法でそうすることはそれほど魅力的ではありません。ライブラリに入れることもできますが、これらの単純な型のためだけに、そのライブラリへの依存関係を追加します。(.NET 4.0にTuple
型が含まれていることを嬉しく思います)しかし、これでも、これらが単純な値であるという事実は解決されません。つまり、単純なタスクの複雑さが増します。
使用されたオプションはout
、呼び出し元が変数に「参照」を渡すことを可能にする修飾子を含めることでした。これにより、関数は、値を返す別の方法として参照される変数を設定できます。値を返すこの方法は、同じ理由でCおよびC ++でもさまざまな方法で利用可能であり、この決定に影響を与える役割を果たしました。ただし、C#の違いは、out
パラメーターの場合、関数は値を何かに設定する必要があることです。そうでない場合は、コンパイラエラーが発生します。これにより、エラーが発生しにくくなりout
ます。パラメーターを設定することで、呼び出し元に値を設定して使用できるようにすることを約束しているため、コンパイラーはその約束を守るようにします。
out
(または)修飾子の一般的な使用法に関する注意事項として、ref
1つまたは2つ以上のout
パラメーターが表示されることはめったにありません。そのような場合、ほとんどの場合、カプセル化タイプを作成する方がはるかに優れています。通常、返す値がもう1つ必要な場合に使用します。
ただし、.NET 4.0で導入された匿名型とタプルが導入されたC#-3.0 / .NET-3.5以降、これらのオプションは、さまざまな型の複数の値をより簡単に(そしてより直感的に)返すための代替メソッドを提供しました。
これを使用するシナリオはたくさんありますが、主なシナリオは、メソッドが複数のパラメーターを返す必要がある場合です。たとえば、typeのTryParse
メソッドを考えてみましょう。int
この場合、例外をスローする代わりに、boolが成功/失敗フラグとして返され、解析されたintがoutパラメーターとして返されます。電話をかけるとint.Parse(...)
、例外が発生する可能性があります。
string str = "123456";
int val;
if ( !int.TryParse(str,out val) )
{
// do some error handling, notify user, etc.
}
確かに、次のTryParse
ような方法のいずれかを見てint.TryParse
ください。
実際には、解析操作が成功したかどうか(戻り値)と、成功した場合はその結果が実際に何であったか(パラメーター)の2つの情報が必要です。out
使用法:
string input = Console.ReadLine();
int value;
// First we check the return value, which is a bool
// indicating success or failure.
if (int.TryParse(input, out value))
{
// On success, we also use the value that was parsed.
Console.WriteLine(
"You entered the number {0}, which is {1}.",
value,
value % 2 == 0 ? "even" : "odd"
);
}
else
{
// Generally, on failure, the value of an out parameter
// will simply be the default value for the parameter's
// type (e.g., default(int) == 0). In this scenario you
// aren't expected to use it.
Console.WriteLine(
"You entered '{0}', which is not a valid integer.",
input
);
}
out
多くの開発者は、パラメータを「コードの臭い」として不平を言っています。しかし、それらは多くのシナリオで断然最も適切な選択である可能性があります。非常に重要な最新の例の1つは、マルチスレッドコードです。多くの場合out
、戻り値では不十分な「不可分」操作を許可するためにパラメーターが必要です。
たとえばMonitor.TryEnter(object, ref bool)
、ロックを取得してアトミックに設定する場合を考えてみます。これは、戻り値が変数bool
に割り当てられる前に必ずロックの取得が行われるため、戻り値だけでは不可能なことです。bool
(はい、技術的ref
にout
は同じではありませんが、非常に近いです)。
もう1つの良い例は、System.Collections.Concurrent
.NET4.0の新しい名前空間のコレクションクラスで使用できるメソッドの一部です。ConcurrentQueue<T>.TryDequeue(out T)
これらは、やなどの同様にスレッドセーフな操作を提供しますConcurrentDictionary<TKey, TValue>.TryRemove(TKey, out TValue)
。
出力パラメーターは、.NETFramework全体にあります。私が最もよく目にする用途のいくつかは、ブール値(解析が有効かどうかを示す)を返すTryParseメソッドであり、実際の結果は出力パラメーターを介して返されます。複数の値を返す必要があるときにクラスを使用することも非常に一般的な場所ですが、このような例では、少し手間がかかります。出力パラメーターの詳細については、C#でのパラメーターの受け渡しに関するJonSkeetの記事を参照してください。
複数の値を返すメソッドがある場合は、単純です。最も「有名な」ケースの1つは、Dictionary.TryGetValueです。
string value = "";
if (openWith.TryGetValue("tif", out value))
{
Console.WriteLine("For key = \"tif\", value = {0}.", value);
}
else
{
Console.WriteLine("Key = \"tif\" is not found.");
}
他の人が言っているように、-outパラメータを使用すると、結果をstruct / classでラップしなくても、メソッド呼び出しから複数の値を返すことができます。
xxx.TryParseメソッドの追加により、文字列値(多くの場合UIから)とプリミティブ型の間で変換するために必要なコーディングが大幅に簡素化されました。
同じ機能を実現するために作成しなければならなかった可能性のあるものの例を次に示します。
/// <summary>
/// Example code for how <see cref="int.TryParse(string,out int)"/> might be implemented.
/// </summary>
/// <param name="integerString">A string to convert to an integer.</param>
/// <param name="result">The result of the parse if the operation was successful.</param>
/// <returns>true if the <paramref name="integerString"/> parameter was successfully
/// parsed into the <paramref name="result"/> integer; false otherwise.</returns>
public bool TryParse(string integerString, out int result)
{
try
{
result = int.Parse(integerString);
return true;
}
catch (OverflowException)
{
// Handle a number that was correctly formatted but
// too large to fit into an Int32.
}
catch (FormatException)
{
// Handle a number that was incorrectly formatted
// and so could not be converted to an Int32.
}
result = 0; // Default.
return false;
}
ここで回避される2つの例外チェックにより、呼び出し元のコードがはるかに読みやすくなります。実際の.NET実装は例外を完全に回避するので、パフォーマンスも向上すると思います。同様に、この例は、IDictionary.TryGetValue(...)がコードをより単純で効率的にする方法を示しています。
private readonly IDictionary<string,int> mDictionary = new Dictionary<string, int>();
public void IncrementCounter(string counterKey)
{
if(mDictionary.ContainsKey(counterKey))
{
int existingCount = mDictionary[counterKey];
mDictionary[counterKey] = existingCount + 1;
}
else
{
mDictionary.Add(counterKey, 1);
}
}
public void TryIncrementCounter(string counterKey)
{
int existingCount;
if (mDictionary.TryGetValue(counterKey, out existingCount))
{
mDictionary[counterKey] = existingCount + 1;
}
else
{
mDictionary.Add(counterKey, 1);
}
}
そして、すべてoutパラメーターに感謝します。
bool Int32.TryParse(String, out Int);
またはDictionary.TryGetValueのようなもの。
しかし、もちろん、これを採用するにはあまり良い方法ではないと思います。もちろん、Try-Catchを回避するためにInt32のようなAPIによって提供されるものを使用することは例外です。
//out key word is used in function instead of return. we can use multiple parameters by using out key word
public void outKeyword(out string Firstname, out string SecondName)
{
Firstname = "Muhammad";
SecondName = "Ismail";
}
//on button click Event
protected void btnOutKeyword_Click(object sender, EventArgs e)
{
string first, second;
outKeyword(out first, out second);
lblOutKeyword.Text = first + " " + second;
}