LoginSignup
1
1

More than 5 years have passed since last update.

C# の練習,落書き帳

Last updated at Posted at 2017-01-03

全体的なこと

O'Reilly プログラミング C# を元に勉強しながらテストコードなどを殴り書きしていくスタイル.

型推論型 var,for, foreach の使い方

型推論型 var の使い方は,Microsoft からガイドライン(https://msdn.microsoft.com/ja-jp/library/bb384061.aspx) に詳細が掲載されている.

  1. var は,基本的に右辺が明確な時のみ利用する.
  2. for, foreach では,初期化子に利用する
  3. 上記以外は,var を用いない.例えば, String s = GetStringSomewhere(); のような,メソッドから受け取るときは var は用いない.

for, foreach の場合

for, foreach は比較的分かりやすい.とにかく var で受け取れば良い.

public static void Main(string[] args)
{
    // new List<Object> で型名が明確になっているので宣言側は var にする.
    // 何でも型は,Object で表現できる.
    var list = new List<Object>();
    // add value           CLR名           C#型
    list.Add("abc");    // System.String   (string)
    list.Add(true);     // System.Boolean  (bool)
    list.Add(100);      // System.Int32    (int)
    list.Add(200u);     // System.UInt32   (uint)
    list.Add(100.5f);   // System.Single   (float)
    list.Add(100.25d);  // System.Double   (double)
    list.Add(100.1m);   // System.Decimal  (decimal)

    String format = "| {0, 6}  |  {1, -15} |";
    Console.WriteLine(String.Format(format, "Value", "GetType"));
    Console.WriteLine(String.Format("|--------:|:-----------------|"));

    // 型推論 var による for, foreach
    //
    // for, foreach における添え字,要素型は var とする
    //    https://msdn.microsoft.com/ja-jp/library/bb384061.aspx

    // e.g. for
    for (var i = 0; i < list.Count; ++i)
    {
        Console.WriteLine(string.Format(format, list[i], list[i].GetType()));
    }

    Console.WriteLine(Environment.NewLine);

    // e.g foreach
    foreach (var l in list)
    {
        Console.WriteLine(string.Format(format, l, l.GetType()));
    }
}

結果(コンソール).GetType は,CLR名を返すんだね.

|  Value  |  GetType         |
|--------:|:-----------------|
|    abc  |  System.String   |
|   True  |  System.Boolean  |
|    100  |  System.Int32    |
|    200  |  System.UInt32   |
|  100.5  |  System.Single   |
| 100.25  |  System.Double   |
|  100.1  |  System.Decimal  |


|    abc  |  System.String   |
|   True  |  System.Boolean  |
|    100  |  System.Int32    |
|    200  |  System.UInt32   |
|  100.5  |  System.Single   |
| 100.25  |  System.Double   |
|  100.1  |  System.Decimal  |

ローカル変数のとき

ローカル変数のときは,少し複雑になる.

整数リテラルの場合

整数リテラル(整数の即値)で宣言したときは,基本的には 32bit 符号付き整数になる.
(まあ,当然と言えば当然かも)

// 整数リテラルで宣言する
//
// これら全ては,Int32, Int64, UInt64 で型推論を試みることを確認する.
// できるだけ Int32 で済ませようとし,Int32 以上ならば Int64,
// それ以上ならば UInt64 になることを確認する.
//
// すなわち,優先度は以下の通りとなる
//   1.   int,  Int32  32bit 符号付き整数
//   2.  long,  Int64  64bit 符号付き整数
//   3. ulong, UInt64  64bit 符号なし整数
var intention_is_sbyte = 128;                  // sbyte  = Int8 のつもり
var intention_is_short = 32767;                // short  = Int16 のつもり
var intention_is_int   = 65536;                // int    = Int32 のつもり
var intention_is_long  = 4294967296;           // long   = Int64 のつもり
var intention_is_ulong = 9223372036854775808;  // ulong = UInt64 のつもり

// 標準出力用のフォーマット
var format = "| {0, -19}| {1, 26:N0} | {2, -15}|";

Console.WriteLine(String.Format(format, "value name",
                  "value", "get type"));

Console.WriteLine("|:-------------------|" +
                  "---------------------------:|" +
                  ":---------------|");

Console.WriteLine(String.Format(format, "intention_is_sbyte",
                  intention_is_sbyte, intention_is_sbyte.GetType()));

Console.WriteLine(String.Format(format, "intention_is_short",
                  intention_is_short, intention_is_short.GetType()));

Console.WriteLine(String.Format(format, "intention_is_int",
                  intention_is_int, intention_is_int.GetType()));

Console.WriteLine(String.Format(format, "intention_is_long",
                  intention_is_long, intention_is_long.GetType()));

Console.WriteLine(String.Format(format, "intention_is_ulong",
                  intention_is_ulong, intention_is_ulong.GetType()));

結果.sbyte, short など,int32 以内に収まる整数型は int32 になる.

| value name | value | get type |
|:-------------------|---------------------------:|:---------------|
| intention_is_sbyte | 128 | System.Int32 |
| intention_is_short | 32,767 | System.Int32 |
| intention_is_int | 65,536 | System.Int32 |
| intention_is_long | 4,294,967,296 | System.Int64 |
| intention_is_ulong | 9,223,372,036,854,775,808 | System.UInt64 |

では,sbyte や short の範囲のときはどうすればいいか.var をやめればよい.
おとなしく,sbyte や short で宣言しろってことですね.

次の場合は混乱するかもしれない.
csharp
Int16 value = 16500;
var whatItWillBe = value + 1;
Console.WriteLine(whatItWillBe);
Console.WriteLine(whatItWillBe.GetType());

結果

16501
System.Int32

はい,int になりました.整数リテラルが int なので,short + int = int となったんでしょうね.
他のプログラミング言語でも 大きい方の型を採用することがほとんどです.
なので,以下の例はコンパイルエラーが出ます.

public static void someFunction(byte b)
{
    Console.WriteLine("0x{0,0:X}", b);
}

public static void Main(string[] args)
{
    byte value         = 128;
    var convertedToInt = value + 1;
    someFunction(convertedToInt);     // convertedToInt は int型なので渡せない.
    someFunction(value + 1);          // 当然,これもエラーになる
    someFunction((byte)(value + 1));  // キャストすれば OK.
}

このように,便利だからと言ってなんでも var を使うと,コンパイルエラーとなります.
引数に渡す変数は,明確に関数の引数に宣言されている変数型を合わせるべきです.

public static void Main(string[] args)
{
    byte value           = 128;
    byte  notBeConverted = (byte)(value + 1);
    someFunction(notBeConverted);     // 大丈夫
}
1
1
0

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
1
1