5
2

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

More than 5 years have passed since last update.

[C#]int.TryParse の out 変数から学ぶ

Last updated at Posted at 2018-08-06

筆者の恥ずかしい失敗談を晒すエントリです。
まずはこちらをご覧ください。

:tea: 問題

このとき isInt と tmp がコンソールに出力する値はなんでしょう?

using System;

public class Hello
{
  public static void Main()
  {
    int tmp = 10;
    bool isInt = Int32.TryParse("six", out tmp);
    Console.WriteLine(isInt);
    Console.WriteLine(tmp);
  }
}

:bulb: 正解

変数 出力される値
isInt false
tmp 0

そんなのは当たり前だ、という賢明な諸氏は特にこの記事から得るものはないのでそっとタブを閉じてやってください。

:warning: 誤答

で、そんなのは当たり前ではなかった筆者の恥晒し誤答はこちら。

変数 出力される値
isInt false
tmp 10

isInt が false になるのは期待どおりですが、問題が out 変数に指定していた tmp で、こちらは 10 が出力される、と思い込んでいました。数値に変換できない値を渡した場合であっても out に代入はされる んですね。なので tmp に予め 10 を格納しておいても全く意味がないということです。

:pencil: 公式

変換に失敗した場合は 0 を格納します。

しっかり書かれてました。みなさん、公式ドキュメントはよく読みましょう(ブーメラン)

:question: ところで 0 はいつ格納されているのか

ちょっと気になったので軽くソースを見てみることにしました。
この記事を参考にさせていただきました。
https://qiita.com/Marimoiro/items/e255eecc265cd5a45025

int は言わずもがな System.Int32 のエイリアスです。
なので今回見たいのは System.Int32 クラスのドキュメントになります。さっそく見てみます。
https://docs.microsoft.com/ja-jp/dotnet/csharp/language-reference/language-specification/types#simple-types

System.Int32.TryParse

実際には Number.TryParseInt32 が実質的な処理を行っているようですね。というわけで次へ進みます。

System.Number.TryParseInt32

https://referencesource.microsoft.com/#mscorlib/system/number.cs,958cb8bc00d00a94
メソッドもそうなんですが、Numberクラス自体も internal であるため、基本はプログラマーが呼び出して使うようなクラスではなさそうですね。んで、問題の out 引数への代入はメソッド開始から3行目で早々に行われていることがわかります。

mscorlib/system/number.cs,1085
result = 0

中の実装まで見なくてもメソッドの挙動から明らかではありますが、out を付けた引数は参照渡しになります。
なのでこの代入によって先ほどの問題の tmp = 10 が書き換えられていることは間違いなさそうです。

追記

@albireo さんからのコメントを参考に、out引数を持つメソッドを自作して確認してみたところ、そもそもout引数に対してメソッド内で何も値を代入しないとコンパイルエラーになることがわかりました。少なくともout引数が何らかの書き換えが行われていることは確実と言えます。

void hoge(ref int refValue, out int outValue)
{
  //これはOK
  if (refValue < 0) {
    refValue = 0;
  }

  if (outValue < 0) { //後述のエラー1
    outValue = 0;
    Console.WriteLine(outValue);//これはエラーにならない
  }

  //後述のエラー2
}
VisualStudioのコンソール
エラー1
  割り当てのない out パラメーター 'outValue' の使用です。
エラー2
  out パラメーター 'outValue' はコントロールが現在のメソッドを抜ける前に
  割り当てられる必要があります。

これでもう同じ失敗は繰り返さないでしょうw
最後まで読んで下さりありがとうございました。

5
2
2

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
5
2

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?