bool / intを返し、実際のオブジェクトを出力パラメーターとして持つメソッドがあるのはなぜですか?


12

私の会社のコードベース(.NET 3.5アプリケーション)のいたるところに次のコードパターンがあります。

bool Foo(int barID, out Baz bazObject) { 
    try { 
            // do stuff
            bazObject = someResponseObject;

            return true;
    }
    catch (Exception ex) { 
        // log error
        return false;
    }
}

// calling code
BazObject baz = new BazObject();
fooObject.Foo(barID, out baz);

if (baz != null) { 
    // do stuff with baz
}

Fooメソッドが単にIDを取得してBazオブジェクトを返す代わりに、使用されていない値を返して実際のオブジェクトをrefまたは出力パラメーターにするのではなく、なぜこれを行うのかを頭に入れようとしています。

私が見逃しているこのコーディングスタイルの隠された利点はありますか?



あなたの例では、baz存在nullと返さboolれるfalse存在同等ではありませんnew BazObject()は決してないnullのでbazObjectExceptionがスローされる前に更新されない限りFoofalseが返さbazれる時は決してなりませんnull。場合、それは途方も役立つだろう仕様については、Foo利用可能でした。実際、これはおそらくこのコードが示す最も深刻な問題です。
スティーブパウエル

これはかなり前のことなので、私の記憶はぼんやりしていますが、例が台無しで、「baz」がヌルではなく「baz」が偽かどうかをチェックしていたと思います。それはVB6と(彼はしなかった)彼のコードを改善するためにわざわざ決して開発者からだったようにいずれの場合においてもパターンはちょうど、私には本当に古風なように見えた
ウェイン・モリーナ

回答:


11

通常、このパターンを使用して、次のようなコードを記述できます。

if (Foo(barId, out bazObject))
{
  //DoStuff with bazobject
}

たとえば、辞書クラスのTryGetValueのCLRで使用されます。それはいくつかの冗長性を回避しますが、outおよびrefパラメーターは常に少し厄介に思えました


1
+1、これは、ブール値とオブジェクトの両方を別々に返すのではなく、ブール値とオブジェクトの両方でオブジェクトを返す傾向があるにもかかわらず、これが理由です
-pdr

コンセンサスは特定の状況を除いてかなり時代遅れであるように見えますが、それが理由を説明しているので、これを答えとしてマークします。
ウェインモリナ

この答えは、このパターンの使用を正当化します。しかし、それがコードベース全体である場合、おそらくショーン側のような悪い習慣です。
コーディズム

11

これは、例外が発生する前の古いCスタイルのコードです。戻り値は、メソッドが成功したかどうかを示し、成功した場合は、パラメーターに結果が書き込まれます。

.netでは、そのための例外があります。このパターンに従う理由はないはずです。

[編集]例外処理には明らかにパフォーマンスへの影響があります。たぶんそれは何か関係があるのでしょう。ただし、そのコードスニペットには、既に例外がスローされています。より適切な場所に引っかかるまで、スタックを上に移動させる方が簡単です。


いいえ。同意できません。予想される条件に対して例外を使用しないでください。たとえば、文字列をintに解析する場合、誰かが解析できない文字列を渡す可能性は常にあります。あなたはそのような場合には例外をスローしてはならない
PDR

それは私が言ったことではありません。OPが投稿したコードを読むと、例外が発生していることが明示的にありますが、メソッドはそれをキャッチし、代わりにfalseを返します。この質問は、予想される条件ではなく、エラー処理に関連しています。
ショーンエドワーズ

ええ、主にデータベースからデータをロードするメソッドなどで使用されているようですif (baz.Select())が、多くの場合、戻り値は単に破棄され、値はnullまたは何らかのプロパティに対してチェックされます。
ウェインモリナ

@Sean、あなたが言っていることを見て、私は「.NETではその目的のために例外がある」というフレーズに反対しているだけです。例外は私にとってまったく異なる目的に役立ちます
-pdr

1
わかりました。無効な引数のコーディングエラーを説明するために、すべてのメソッドにブール値を追加するだけではいけないのは事実です。しかし、メソッドへの入力が開発者ではなくユーザーからのものである場合は、間違った場合に例外をスローせずに入力を処理できるようにする必要があります。
pdr

2

コードスニペットを考えると、完全に無意味に見えます。私にとって、最初のコードパターンは、BazObjectのnullが許容されるケースであり、boolの戻り値がフェイルケースを安全に判断する手段であることを示唆しています。次のコードが:

// calling code
BazObject baz = new BazObject();
bool result = fooObject.Foo(barID, out baz);

if (result) { 
    // do stuff with baz
    // where baz may be 
    // null without a 
    // thrown exception
}

これは、この方法で行う方が理にかなっています。おそらくこれは、オブジェクトパラメータがC#で実際にどのように機能するかを理解せずに、bazが参照で渡されることを保証するために使用する前の誰かのメソッドです。


私はそれがチームの現在のメンバーによって書かれたと思います。おそらくそれはO_Oについて心配する必要があるものです
ウェインモリナ

@ウェインM:潜在的なトレーニングの機会よりも心配は少ない:)
ジョエル・イーサートン

1

呼び出し側が、返された型が参照型であるか値型であるかを気にする必要がない場合に、このパターンが役立つことがあります。このようなメソッドを呼び出して値型を取得する場合、その値型には確立された無効な値(例:double.NaN)が必要か、成功を判断する他の方法が必要です。


それは理にかなっている。少し奇妙に思えますが、それは正当な理由のように聞こえます。
ウェインモリナ

0

このアイデアは、プロセスが成功したかどうかを示す値を返し、次のようなコードを許可することです。

Baz b;
if (fooObject.foo(id, out b)) {
   // do something with b
}
else {
   Error.screamAndRun("object lookup/whatever failed! AAaAAAH!");
}

オブジェクトをnullにできない場合(この例では正しいように見えます)、次のように実行することをお勧めします。

Baz b = fooObject.foo(id);
if (b != null) {
   // do something with b
}
else {
   Error.screamAndRun("object lookup/whatever failed! AAaAAAH!");
}

オブジェクト nullになる可能性がある場合、例外を使用する方法があります。

try {
   Baz b = fooObject.foo(id);
}
catch (BazException e) {
   Error.screamAndRun("object lookup/whatever failed! AAaAAAH!");
}

これは、例外のないCで使用される一般的なパターンです。関数がエラー状態を返すことができます。例外は一般的にはるかにクリーンなソリューションです。


特に、コードがすでに例外をスローしているためです。
デビッドソーンリー
弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.