概要

前回(『プログラミング C#』 その1 C# の基礎)のつづき。ぱらぱら進めるぞー。

 

流し読みノート

変数宣言は型名か var で行う

Python では a = 1 だったところを C# では int a = 1; あるいは var a = 1; とする。 var はどの型であっても汎用的に使える便利くんだけど、「は?」って感じだよな。 var を使ったら型がある意味がないじゃん。だから var を使うのは以下のようなときのみだ。

// こんなの無駄だから……
List<int> numbers = new List<int>();

// var を使う。
var numbers = new List<int>();

それなら納得だ。あと「匿名型」というものに使うらしい。というか匿名型が追加されたときに var が追加されたらしいし。

 

ブロック

こういう書き方ができる。

{
    int a = 1;
}
{
    string a = "aaaa";
}

同じスコープにあるのに、同じ名前の変数を複数宣言できるのだ。あ、これは便利かも。名前がどうでもいい変数を表す _ なんかと組み合わせれば、コードが見やすくなりそう。

 

プリプロセッサディレ……ぷりぷり……え?

プリプロセッサディレクティブね。これは Python をいじってるときはまったく思いつかなかったことだけれど、コードを実行する前に機能する if 文を書く方法だ。整理すると「プリプロセッサ」が「メインのプログラムが動く前に動くもの」で、「ディレクティブ」は下に示す # から始まる実際の命令行のこと。

#if DEBUG
// DEBUG コンパイルシンボルがあるとき実行される
#elif STAGING
// STAGING コンパイルシンボルがあるとき実行される
#else
// その他のとき実行される
#endif

Visual Studio を使うと、コードを Debug や Release といった環境設定ごとにコンパイルできるから、 #if DEBUG の中に Debug 環境でのみ実行してほしいコードを書けばいいのだ。 Python の Django でも環境ごとに設定を変えるなんてことはした(DjangoNote 3 設定ファイルを複数つくる)けれど、うーむ、こちらもなかなか分かりやすい。

肝心の DEBUG やら STAGING といった「コンパイルシンボル」は Visual Studio で設定する。プロジェクトのプロパティノードをダブルクリック > ビルドタブをクリック、から……。

if やら else の他にもプリプロセッサディレクティブはある。

// warning ディレクティブ
#warning ここに書いたメッセージがビルド時に表示されるらしいから、 TODO を書くのにいいんじゃない?

// error ディレクティブ
#if SILVERLIGHT
    #error SILVERLIGHT はサポートしてないよ!
#endif

// line ディレクティブ、よくわかんない。
#line 123 "Foo.cs"

// pragma ディレクティブは、「この変数、宣言してるけど使ってないよ」とかのコンパイラの警告を無効化する。
// 言うまでもなく、あんまり無効にしないほうがいい。
#pragma warning disable 168
int x;

// region ディレクティブは、とくになにか動作するものではないけど、 Visual Studio 上でコードを折り畳めるようになる。
// コーディングの補助にどうぞ。
#region 機能 A に関するコード
// 機能 A
#endregion

 

C# の型と CLR の型の対応

C# CLR 範囲
byte System.Byte 0 ~ 255
int System.Int32 -2147483648 ~ 2147483647
long System.Int64
float System.Single
double System.Double

こういうふうに、 CLR が共通の型を管理してくれるから、 C# 以外の言語とも連携ができるわけね。前回おさえた CLR の意味をちゃんと理解して読めてて満足。

 

整数のオーバーフロー

↑にちょっと示したように、 int の限界値は 2147483647 だ。それに 1 足すと -2147483648 になる。これをオーバーフローという。このとき例外は発生しないので、いつの間にか予期せぬ状況になっちゃってるかもしれない。そんなときに checked コンテキストを使う。

int i = 2147483647;
checked
{
    // ここでロールオーバーが起こらず OverflowException が起こる。
    int j = i + 1;
    Console.WriteLine(j);
}

 

BigInteger

  • そんな面倒なことは考えなくていい System.Numeric.BigInteger は限界のない整数。
  • System.Numeric は参照追加が必要。
  • メモリの許す限り巨大な整数を扱える。
  • ただし組み込みデータ型ではなくクラスなので動作は遅い。

 

フォークスルー

C 言語だと、 switch 文で break を書かないと次の case へ自動で移るんだって。それをフォークスルーという。 C# はそれをサポートしてなくて、 goto case キーワードを使ってフォークスルーを実現するらしい。うん、より明示的にするのは賛成だ。

switch (x)
{
    case "One":
        Console.WriteLine("1");
        goto case "Two";
    case "Two":
    case "Three":
        Console.WriteLine("2 or 3");
        break;
}

ちなみに Python には switch はないけど、こういうふうに書けるよ。フォークスルーに相当するものはないと思うな……。

if x in ['One']:
    print('1')
elif x in ['Two', 'Three']:
    print('2 or 3')

 

その他つまみ読み

  • string + int すると int が自動で string に化けるんだって。それを実装するなら Python みたいに f'string{int}' を実装したほうがいいと思うけど。
    • と思って調べたら、ちゃんと文字列に変数を埋め込む方法もあった。 $@"strings{int}tring" こうするんだって。
  • C# は Python のように if (リスト) で空っぽ判定とかできない。