私はこのコードを持っています...
var i = int.MinValue;
var s = string.Empty;
int.TryParse(s, out i);
TryParse
ステートメントの後、i
変数の値が上書きされ ( as zero
)、以前の値が失われます。
これはバグですか?out
いいえの場合、パラメーターとして渡された変数を再初期化する必要があった理由について、実装の詳細はありますか?
全体的なポイントは、この値を上書きout
することを保証することです(少なくとも C# レベルでは... IL レベルではありません)。これの目的は、「明確な割り当て」を許可しながら、不要な割り当てを回避することです。例えば:
int i; // note: not assigned
var s = string.Empty;
// here "i" is not "definitely assigned"
int.TryParse(s, out i);
// here "i" is "definitely assigned"
アイデアは、戻り値を使用することです。たとえば、次のようになります。
if(int.TryParse(s, out i)) {
// here "i" makes sense; feel free to use it
} else {
// here you shouldn't use the value of "i"
}
特定のケースでは、次の順序で並べ替えることができます。
if(!int.TryParse(s, out i)) i = int.MinValue;
特に、(少なくとも C# では) メソッドは値を割り当てる必要があり、入力値を使用できないことに注意してください。例えば:
static void Foo(out int i) {
return; // error: hasn't assigned to i
}
static void Bar(out int i) {
int j = i; // error: cannot read from "i" until Bar has assigned a value
i = j;
}
static void Baz(out int i) {
i = 0; // note that after this assignment, code in Baz can read from "i"
}
とは対照的ref
です。ref
値を渡すときは、呼び出し側で確実に割り当てる必要があります。メソッド自体は、入力値を参照する場合と参照しない場合があり (選択した場合)、新しい値を割り当てる場合としない場合があります (選択した場合) 。例えば:
int i;
SomeMethod(ref i); // illegal - "i" is not definitely assigned
int i = 0;
SomeMethod(ref i); // legal
と:
static void Foo(ref int i) {
return; // perfectly legal to not look at "i" and/or not assign "i"
}
static void Foo(ref int i) {
i = i + 1; // perfectly legal to look at "i" and/or assign "i"
}
これはバグではありません。変換に失敗するとゼロが返されます。この場合の関数の戻り値は false になります。
このメソッドが戻るときに、変換が成功した場合は s に含まれる数値に相当する 32 ビットの符号付き整数値を含み、変換が失敗した場合は 0 を含みます。s パラメータが null の場合、正しい形式でない場合、または MinValue 未満または MaxValue より大きい数値を表している場合、変換は失敗します。このパラメーターは初期化されずに渡されます。
out 引数として渡される変数は、渡す前に初期化する必要はありませんが、呼び出し元のメソッドは、メソッドが を返す前に値を割り当てる必要があります。
Int32.Parse
ゼロで初期化しdefault(int)
ます。
s
このメソッドが戻るときに、変換が成功した場合は に含まれる数値に相当する 32 ビットの符号付き整数値を含み、変換が失敗した場合は 0を含みます。
out パラメータなのでバグではありません。演習として、out パラメーターの値を設定しない C# を書いてみてください。(ヒント: それは不可能です) したがって、観察される結果は唯一の論理的な結果です。out 変数は「再初期化」されておらず、単に初期化されているだけです。
TryParse が ref int を取るように書かれていれば、あなたが望むことは可能だったでしょう。個人的には、ここでは int の方が優れていると思います。