読者です 読者をやめる 読者になる 読者になる

プログラミングC#読解メモ 第二章

EffecticeC#も途中で頓挫しててあれなんだけど、「プログラミングC#第七版」が最近出て、C#好きなので買った。なんとなく一番好きな言語になってしまって、結局一番勉強してる。不自由な言語だどうたらいう人がいるけど、好きになってしまっては仕方ない。

さて、第一章は「Hello World」を書いてみよう的なアレだったので飛ばす(なんかテストとか出てきて謎の高度さがあったが)。願わくばこの記事がたくさんのC#erの眼にとまり、マサカリがたくさん飛んできますように。

{}で適当なブロックが作れるのは知らなかった。何かしらのブロックを再現する機能(クラスやら関数やらfor/ifやら)においてのみブロックはできると思ってたら普通に使えた。あんまり使い道は思い浮かばないけど。
ちなみに

{
  var hoge = 100;
}
var hoge = 10;

が禁止されてるのはあんまり納得いかなかった。理屈ではなくて、理念的に。
まぁそうなってるものは仕方ないのだけど。

ステートメントと式の細かい話はちょっといいや。重箱の隅のような感じがするし。
プリプロセッサディレクティブは、今まで全然使ってなかった。
プリプロセッサディレクティブとは、

#if DEBUG
            Console.WriteLine("DEBUGなう");
#endif
            Console.WriteLine("ぽよ");

みたいなやつのことである。DEBUGビルドのときのみ、「DEBUGなう」は出力される。
ただし、EffectiveC#によると、これは推奨される書き方ではない。「属性」を使うべきらしい。
属性はだいぶ後の章で出てくるみたいだけど、とりあえず上のやつはこんな感じになる。

        static void Main(string[] args)
        {
            DebugMessage();
            Console.WriteLine("ぽよ");
        }

        [System.Diagnostics.Conditional("DEBUG")]
        static private void DebugMessage()
        {
            Console.WriteLine("DEBUGなう");
        }

こちらのほうが優れている理由はまぁいろいろあるらしい。ざっくりいうとパフォーマンスの問題と可読性の問題だ。パフォーマンスの問題(メモリへのロードとか)は難しいから置いておくとしても、可読性の差については少し想像してみればわかる。コードのあちこちに#if~#endifブロックが遍在しまくってると混乱しそうだ。
ちなみに条件は論理和でつなぐことはできるが、論理積は使えない。もし使いたければそれ用のプリプロセッサを定義する必要がある。

[Conditional("DEBUG"),Conditional("TRACE")]//これはORで繋いでる。

//&&を使いたいのなら、
#if (VAR1 && VAR2)
#define BOTH
#endif

[Conditional("BOTH")]

コンパイル用の指示ディレクティブ以外にもディレクティブは存在する。

//#errorディレクティブはエラーを出す。
#error このコードはやばい
//#warningディレクティブは警告を出す。
#warning ヤバイ
//#lineディレクティブはエラー箇所を明示的に指示する。
#line 10000 "hoge.cs"
//とあるエラーコード
/*
 *エラーの場所がhoge.csファイルの10000行目と表示される。
 *動的にコード生成したり入力ファイル等の外的要因を指摘するのに便利。
 */
//#pragmaディレクティブは指定したコンパイラの警告を無効にできる。
#pragma warning disable 168  //警告番号
//エラーのヘルプから警告番号見れるらしいんだけどVS2013のヘルプだと出てこないっぽい。おいおい。

あと#pragmaにはもう一つ使い方があるらしいけど触れられてはいない。不要だと判断されているのだろうか。いちいち全項目についてMSDNを見ていくわけにもいかないから、この本に書いてあることはそんなに優先度高くないと思いたい。

checkedコンテキスト
型キャストによるオーバーフローを感知して例外投げてくれる。

var hoge = checked(hoge*100000);

もともと暗黙的にキャスト可かどうかというのはビット数しか見てないらしいので、割とオーバーフローは起こりうるようだ。だけど一応ビット数はそろってるので結果わけのわからない値が入ってしまう。それはやばいんだけど、これを付けてると感知して例外を投げてくれる。
以下のようにブロックを作ることもできる。

checked
{
  var hoge = fuga;
  var poyo = piyo;
}

uncheckedキーワードも存在する。checkedする範囲の広さ、数によっては全体をcheckedブロックで囲ってからunchekedを一部に適用したほうが早いかもしれない。
BigIntegerは動的に大きさが変わる数値型。
さてこの二つのテク、使えるんなら使ったほうがいい気もするが、めっちゃ処理が重くなるそうな。
実行時間のと安全性のトレードオフを考えて使いましょう。
null合体演算子

string notnull = str ?? "";

三項演算子の親戚みたいなもので、意味は下のコードと同じ。

string notnull;
if(s != null)
  notnull = str;
else
not null = "";
//または、
string notnull = str == null ? "" : str;

as演算子と一緒に使うと幸せになれるかも。

今日はここまで。だるくなってきたらキャッチーな章にワープするかもしれない。
別の書くべき文章があるのになぁ……
string