出力パラメーターをいつ使用する必要があるのか わかりません。複数の型を返す必要がある場合は、結果を新しい型に個人的にラップします。
私はこのような方法を見てきました、
public void Do(int arg1, int arg2, out int result)
それが実際に理にかなっている場合はありますか?
どうですかTryParse
、ParseResult
型を返さないのはなぜですか? または新しいフレームワークでは、null 許容型を返しますか?
関数がある場合は Out が適切でありTryNNN
、関数が成功しなくても out-parameter が常に設定されることは明らかです。これにより、後でコード内で null に対してチェックを行う必要がなくなり、宣言したローカル変数が設定されるという事実に依存することができます。(以下のコメントは、パラメーターが に設定される可能性があることを示しているnull
ため、呼び出している関数のドキュメントを確認して、これが当てはまるかどうかを確認することをお勧めします。) コードが少し明確になり、読んだ。別のケースは、次のようなメソッドの条件でデータとステータスを返す必要がある場合です。
public bool DoSomething(int arg1, out string result);
この場合、リターンは関数が成功したかどうかを示すことができ、結果は out パラメータに格納されます。確かに、関数が単純に を返す方法を設計できるため、この例は不自然string
ですが、アイデアは理解できます。
欠点は、それらを使用するためにローカル変数を宣言する必要があることです。
string result;
if (DoSomething(5, out result))
UpdateWithResult(result);
それ以外の:
UpdateWithResult(DoSomething(5));
ただし、それは欠点ではないかもしれません。それは、目的のデザインによって異なります。DateTime の場合、両方の手段 (Parse と TryParse) が提供されます。
ほとんどのものと同様に、それは依存します。オプションを見てみましょう
TryParse の場合、out パラメーターを使用すると効率的です。(32b マシンでは) 16B のオーバーヘッドになる新しい型を作成したり、呼び出し後にガベージ コレクションを行うパフォーマンス コストを負担したりする必要はありません。たとえば、TryParse はループ内から呼び出すことができます。したがって、ここでは out params ルールが適用されます。
ループ内で呼び出されない関数 (つまり、パフォーマンスは大きな問題ではない) の場合、単一の複合オブジェクトを返す方が「クリーン」になる可能性があります (見る人にとって主観的です)。匿名型と動的型付けを使用すると、さらに簡単になる可能性があります。
ノート:
out
params には、従わなければならないいくつかのルールがあります。つまり、コンパイラは、関数が終了する前に値を初期化することを保証します。したがって、解析操作が失敗した場合でも、TryParse は out パラメータを何らかの値に設定する必要があります。out は、TryParse のようにブール値と値の両方を返す必要がある場合に便利だと思いますが、コンパイラが次のようなことを許可してくれると便利です。
bool isValid = int.TryParse("100", out int result = 0);
確かに、out パラメータは、投稿した例のように、複数の値を返す必要があるメソッドがある場合に使用することを目的としています。
public void Do(int arg1, int arg2, out int result)
値を 1 つしか返さないため、out パラメータを使用してもあまり意味がありません。out パラメータを削除して int 戻り値を設定すると、このメソッドをより適切に使用できます。
public int Do(int arg1, int arg2)
out パラメータにはいくつかの利点があります。
結論として、私は基本的にプライベート APIで out params を使用して、複数の戻り値をラップする個別の型を作成しないようにしています。また、パブリック API では、TryParse パターンに一致するメソッドでのみそれらを使用しています。
常にタイプを作成すると、アプリケーションが混乱してしまう可能性があります。
ここで述べたように、典型的な使用例の 1 つは、TrySomething
成功の指標として bool を返し、次に実際の値を返したいメソッドです。また、if ステートメントの方が少しすっきりしていることもわかりました。とにかく、3 つのオプションはすべてほぼ同じ LOC を持っています。
int myoutvalue;
if(int.TryParse("213",out myoutvalue){
DoSomethingWith(myoutvalue);
}
vs.
ParseResult<int> myoutvalue = int.TryParse("213");
if ( myoutvalue.Success ) {
DoSomethingWith(myoutvalue.Value);
}
vs.
int? myoutvalue = int.TryParse("213");
if(myoutvalue.HasValue){
DoSomethingWith(myoutvalue.Value);
}
「Nullable 型を返さない理由」については、TryParse は Framework 1.x 以降に存在しますが、Nullable 型は 2.0 に付属しています (ジェネリックが必要なため)。では、なぜ不必要に互換性を壊したり、一部の型で TryParse 間の不整合を導入し始めたりするのでしょうか? 独自の拡張メソッドをいつでも記述して、既存の機能を複製できます (実行/実行しないことの背後にある理由を含む、無関係な主題に関するEric Lipperts の投稿を参照してください)。
もう 1 つの使用例は、関連のない複数の値を返す必要がある場合です。その場合でも、メソッドがやりすぎている可能性があるというアラームがトリガーされます。一方、メソッドが高価なデータベースまたは Web サービス呼び出しのようなものであり、結果をキャッシュしたい場合は、それを行うのが理にかなっています。もちろん、型を作成することもできますが、これはアプリケーションにもう 1 つの型を作成することを意味します。
値を返すためだけに型を作成するのは、私には少し苦痛に思えます:-) まず、値を返すための型を作成する必要があります。次に、呼び出し元のメソッドで、返された型の値を必要な実際の変数に割り当てます。
出力パラメーターは、使用するのが簡単です。
はい、それは理にかなっています。これを例にとります。
String strNum = "-1";
Int32 outNum;
if (Int32.TryParse(strNum, out outNum)) {
// success
}
else {
// fail
}
戻り値のある通常の関数で操作が失敗した場合、何を返すことができますか? 失敗を表すために -1 を返すことは絶対にできません。なぜなら、失敗の戻り値と、最初に解析されていた実際の値との間に区別がないからです。これが、成功したかどうかを確認するためにブール値を返す理由です。成功した場合は、「戻り値」が安全に割り当てられています。
TryParse 関数の out パラメーターに null を渡すことができないのは、私を悩ませます。
それでも、場合によっては、2 つのデータを含む新しい型を返す方が好まれます。特に、それらがほとんど無関係である場合、または 1 つのピースが 1 回の操作ですぐに必要になるだけである場合. TryParse 関数の結果の値を保存する必要がある場合は、対処しなければならないランダムな ResultAndValue クラスよりも、out パラメーターを使用する方が好きです。
メソッド名を読み取ることが、メソッドの出力が何であれ、特に結果を返すだけでなくコマンドを実行するメソッドの場合よりも重要な場合は、読みやすさのためにoutパラメーターを使用することがあります。
StatusInfo a, b, c;
Initialize(out a);
Validate(a, out b);
Process(b, out c);
対。
StatusInfo a = Initialize();
StatusInfo b = Validate(a);
StatusInfo c = Process(b);
少なくとも私は、スキャンするときに各行の最初の数文字に重点を置いています。いくつかの "StatusInfo" 変数が宣言されていることを確認した後、最初の例で何が起こっているかを簡単に知ることができます。2 番目の例で最初に目にするのは、多数の StatusInfo が取得されていることです。メソッドがどのような影響を与える可能性があるかを確認するには、もう一度スキャンする必要があります。