C#_変数宣言と型・キャスト


C#の基本的な知識からおさらいしていきます。

全くプログラミングしたことない人でも分かる内容にすることができるかどうか自分なりの読解力の確認も兼ねて

本文は以下の記事の内容を前提に記述しています。

* [Win10+VSCodeでC#開発環境構築](https://qiita.com/MtBigYashi/items/dc0a6d970266a56d507e)

## エントリポイント

"dotnet new console -o HelloWorld"によって新たにプロジェクトを作成した場合、
Program.csファイルに下記のようなプログラムが書かれています。

```C#:Program.cs
using System;

namespace HelloWorld
{
    class Program
    {
        static void Main(string[] args)
        {
            Console.WriteLine("Hello World!");
        }
    }
}
```

コンパイラ言語であるC#には"エントリポイント"という、「プログラムが開始するスタート地点」が存在します。
※1. インタプリタ言語は基本的にファイルの先頭から開始します
※2. コンパイラ言語とインタプリタ言語の違いについてはここでは深く触れません。参考URLだけ貼っておきます。

* [インタプリタ言語とコンパイラ言語 (Qiita)](https://qiita.com/tomokichi_ruby/items/73b0e7924a9f83fe45c6)
* [コンパイラとインタプリタの違いは？ (じゃぱざむ)](https://jpazamu.com/interpreter-compiler)

C#のエントリポイントは下記の通りMainと書かれている部分になるので、その中に書かれているコードがプログラム実行時に処理されていきます

```C#:Program.cs
static void Main(string[] args)
{
    // 何らかの処理
}
```

## 標準出力

今、この中に記述されている「Console.WriteLine("Hello World!")」とは、コンソールに"Hello World!"と表示するという命令文になります。
ここでは、コンソールへの表示のことを"標準出力"と呼びます。
※詳しくは下記サイトなどを参照ください

* [標準入力・標準出力ってなに? (Qiita)](https://qiita.com/angel_p_57/items/03582181e9f7a69f8168)
* [標準出力とは (IT用語辞典)](http://e-words.jp/w/%E6%A8%99%E6%BA%96%E5%87%BA%E5%8A%9B.html)

![1.PNG](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/782968/a8fee714-e025-fec8-250a-4141b618a331.png)

文字列以外にも数値や論理値を表示することも可能です。

```C#:Program.cs
Console.WriteLine("Hello World!");
Console.WriteLine(5);
Console.WriteLine(9.8);
Console.WriteLine(false);
```

```TXT:出力
> Hello World!
> 5
> 9.8
> False
```

## 変数と型

さて、コンソールに表示する内容をただただ直書きしていくのはツラいので変数を使っていきましょう

```C#:Program.cs
string a = "Hello World!";
int b = 5;
double c = 9.8;
bool d = false;
Console.WriteLine(a);
Console.WriteLine(b);
Console.WriteLine(c);
Console.WriteLine(d);
```

```TXT:出力
> Hello World!
> 5
> 9.8
> False
```

さて、出力は全く同じですがa~dの変数に値を入れて、変数を使用してコンソールへの表示を行っています。
変数を定義する部分を **"宣言"** と呼び、変数へ値を入れることを **"代入"** と呼びます。

変数宣言時に出てきたstring, int, double, boolなどがそれぞれの変数の **"型"** といい、変数を使う場合には必ず"型"とセットにしなければいけません。

C#の型は「値型」と「参照型」に分かれており、次表に示す型を **"値型"** と呼び、型名と表現できる値の範囲は表の通りです。
宣言した型の表現可能な範囲を超えた値を入れようとするとエラーが起きてしまいます。

|型名|値|備考|
|:---:|:---:|:---:|
|bool|true / false|2値|
|char|文字|16bit Unicode文字|
|sbyte|-128 ~ 127|符号つき8bit整数|
|byte|0 ~ 255|符号なし8bit整数|
|short|-32,768 ~ 32,767|符号つき16bit整数|
|ushort|0 ~ 65,535|符号なし16bit整数|
|int|-2,147,483,648 ~ 2,147,483,647|符号つき32bit整数|
|uint|0 ~ 4,294,967,295|符号なし32bit整数|
|long|-9,223,372,036,854,775,808 ~ 9,223,372,036,854,775,807|符号つき64bit整数|
|ulong|0 ~ 18,446,744,073,709,551,615|符号なし64bit整数|
|decimal|-79,228,162,514,264,337,593,543,950,335 ~ 79,228,162,514,264,337,593,543,950,335|有効桁数28桁以上の10進数実数|
|float|-3.4028235E+38 ~ 3.4028235E+38|単精度浮動小数点数|
|double|-1.7976931348623157E+308 ~ 1.7976931348623157E+308|倍精度浮動小数点数|

値型だけでも数が多いですが、実際のところそこまで厳密に値の範囲を制限したい場面は少ないので、
整数表現にはintを、実数表現にはdoubleを使うということを覚えられれば十分です。

上記、値型以外の型を **"参照型"** と呼び、多種多様な型が存在しますが、"string"=文字列型も参照型の一種となります。
また、参照型は自分で新たに作り出すことも可能です。

* [組み込み型 (Microsoft Docs)](https://docs.microsoft.com/ja-jp/dotnet/csharp/language-reference/builtin-types/built-in-types)

さて、ただ単に直書きを変数にしただけではまだ特にメリットが分からないので計算もさせてみます。

```C#:Program.cs
int a = 14;
int b = 5;
Console.WriteLine(a + b); //  和 ：14 + 5
Console.WriteLine(a - b); //  差 ：14 - 5
Console.WriteLine(a * b); //  積 ：14 * 5
Console.WriteLine(a / b); //  商 ：14 / 5
Console.WriteLine(a % b); // 剰余：14 % 5
```

```TXT:出力
> 19
> 9
> 70
> 2
> 4
```

おかしなことに気づいたでしょうか？「14 / 5 = 2」になってしまっています。
これはC#に限らずですが、プログラミングでは基本的に整数型による計算の結果は整数型になるという決まりがある為です。

理論的には14 / 5 = 2.8になりますが、これを"整数"で表現するために小数部分を切り捨てし、2となります。（四捨五入ではなく切り捨てです）
試しに実数型であるdouble型で同じ計算をしてみると

```C#:Program.cs
double a = 14;
double b = 5;
Console.WriteLine(a / b); //  商 ：14 / 5
```

```TXT:出力
> 2.8
```

となることが確認できると思います。

## キャスト（型変換）

別々の値型でも、ある一定の条件を満たせば型を変換することができます。これを **"キャスト"** と呼びます。

```C#:Program.cs
double a = 5;
int b = (int)a;
double c = b;
Console.WriteLine(a/2);
Console.WriteLine(b/2);
Console.WriteLine(c/2);
```

```TXT:出力
> 2.5
> 2
> 2.5
```

(int)を付けることでdouble型である a をint型に変換して b とすることができました。これを **"明示的キャスト"** と呼びます。
一方で int型である b をそのままdouble型である c に代入しています。これを **"暗黙的キャスト"** と呼びます。

最初に"一定の条件を満たせば"と言いましたが、その条件とは下記のとおりです。

* キャスト前よりもキャスト後の値の範囲が広い場合には暗黙的キャストが可能
* キャスト前よりもキャスト後の値の範囲が狭い場合には明示的キャストが必要

※暗黙的キャスト可能な場合に明示的にキャストを書いても問題ありません。

上記の例では、「intの範囲32bit」＜「doubleの範囲64bit」なのでint→doubleへは暗黙的キャストが可能ですが、その逆では明示的キャストが必要になります。
型の範囲が狭まるということは、元々の変数では表現できていた情報を失ってしまったり、変換時に許容範囲外の値を入れようとしてエラーが起きてしまったりする可能性があります。

```C#:Program.cs
double a = 9.81828;   // 
int b = (int)a;       // 9 （0.81828の損失）
double c = 5000000000;// 50億
int d = (int)c        // エラー（オーバーフロー）
```

また、明示的キャストが必要な場合にキャストを付けなかった場合には、コンパイルエラーが発生して警告されます。

```C#:Program.cs
double a = 5;
int b = a;
// コンパイルエラー
//   型 'double' を 'int' に暗黙的に変換できません。
//   明示的な変換が存在します (cast が不足していないかどうかを確認してください)）
```

まずは変数宣言と型、キャストについてここまで。