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