ベストプラクティス:関数の戻り値またはbyref出力パラメーター?
-
05-07-2019 - |
質問
FindSpecificRowValueという関数を使用して、データテーブルを取得し、特定の値を含む行番号を返します。その値が見つからない場合は、呼び出し元の関数にそのことを示したいと思います。
次への最善のアプローチ:
- 見つからない場合はfalse、見つかった場合はtrue、見つかった行番号をbyref / outputパラメーターとして返す関数を記述する、または
- intを返し、行の値が見つからない場合は-999を返し、見つかった場合は行番号を返す関数を作成します。
解決
個人的には、そのメソッド名でも行いません。
代わりに2つのメソッドを作成します:
TryFindSpecificRow
FindSpecificRow
これはInt32.Parse / TryParseのパターンに従い、C#では次のようになります。
public static Boolean TryFindSpecificRow(DataTable table, out Int32 rowNumber)
{
if (row-can-be-found)
{
rowNumber = index-of-row-that-was-found;
return true;
}
else
{
rowNumber = 0; // this value will not be used anyway
return false;
}
}
public static Int32 FindSpecificRow(DataTable table)
{
Int32 rowNumber;
if (TryFindSpecificRow(table, out rowNumber))
return rowNumber;
else
throw new RowNotFoundException(String.Format("Row {0} was not found", rowNumber));
}
編集:質問により適したものに変更されました。
他のヒント
失敗した関数は例外をスローする必要があります。
失敗が予想されるフローの一部である場合、帯域外の値を返すことは問題ありませんが、帯域外の値を事前に決定できない場合は例外です。その場合、例外をスローする必要があります。
オプションから選択する必要がある場合、オプション2を選択しますが、-999ではなく定数を使用します...
戻り値を Nullable として定義し、Nothingを返すこともできます。何も見つからない場合。
オプション2を選択します。-999ではなく、-1を使用すると思います。
リチャード・ハリソンは、名前付き定数が裸の-1または-999よりも優れていることは正しいです。
2、または戻り値が値が見つかったかどうかを示す他のバリエーションを使用します。
関数が返す(または参照を提供する)行の値は、値が見つかったかどうかをすでに示しているようです。値が見つからなかった場合、値を含まない行番号を指定しても意味がないように思われるため、戻り値は-1、Null、または特定の言語に適した他の値でなければなりません。それ以外の場合、行番号が返されたという事実は、値が見つかったことを示します。
したがって、値が見つかったかどうかを示すために、別の戻り値は必要ないようです。ただし、特定の言語のイディオムに適合し、その中で関数呼び出しが実行される方法であれば、タイプ1が適切な場合があります。
Go with 2)しかし、-1(または行への参照を返す場合はnull参照)を返します。 。
BTW -1はより受け入れやすく、広く使用されている「マジックナンバー」です。 -999よりも、それが「正しい」理由の唯一の理由です。 (そこに使用されている引用符は理由があります)。
しかし、これの多くはあなたが期待することと関係しています。アイテムは常にそこにあるべきですが、どこにいるのかわかりませんか?その場合、通常どおりインデックスを返し、ない場合はエラー/例外をスローします。
この場合、アイテムはそこにない可能性があり、それは問題ない状態です。これは、データテーブルにバインドするGridViewで選択されていない値のエラートラップです。
まだ言及されていない別のいくつかの可能性:
// Method 1: Supports covariance; can return default<T> on failure. T TryGetThing(ref bool success); // Method 2: Does not support covariance, but may allow cleaner code in some cases // where calling code would use some particular value in in case of failure. T TryGetThing(T DefaultValue); // Method 3: Does not support covariance, but may allow cleaner code in some cases // where calling code would use some particular value in case of failure, but should // not take the time to compute that value except when necessary. T TryGetThing(Func<T> AlternateGetMethod); // Method 4: Does support covariance; ErrorMethod can throw if that's what should // happen, or it can set some flag which is visible to the caller in some other way. T TryGetThing(Action ErrorMethod);
最初のアプローチは、Microsoftが共変インターフェイスのサポートが存在する前に開発した方法の逆です。最後はいくつかの点で最も用途が広いですが、使用するたびにいくつかの新しいGCオブジェクトインスタンス(クロージャとデリゲートなど)の作成が必要になる可能性があります。