型推論
varキーワードを使って変数を宣言すると、右辺の値を自動的に判別して変数を宣言する。
using System; namespace Sample { class Program { static void Main(string[] args) { var i = 10; var c = 'c'; var s = "str"; Console.WriteLine(i.GetType()); // System.Int32 Console.WriteLine(c.GetType()); // System.Char Console.WriteLine(s.GetType()); // System.String } } }
識別子の規則
正確な規則はUnicodeの話が入るのでややこしいのだけど、最低限覚えておく必要があるのは以下の規則。
- 1文字目は半角英字もしくは_(アンダーバー)。正規表現:
[a-zA-Z_]
- 2文字目以降は、上記に加えて半角数字も可。正規表現:
[0-9a-zA-Z_]
- ただし、「int」のように言語のキーワードとして使用される単語は不可
- @をつけることで言語のキーワードを変数名に使うことができる。「int @int = 1」はOK
- ただし、「int」のように言語のキーワードとして使用される単語は不可
本書では、1文字目に使える文字は「可読文字もしくはアンダーバー」、と書いていますが、「可読文字」は一般的な用語ではなく、半角数字を含まないことを予期しづらいと思います。「ユニコード文字を識別子に使わない」という制約を加えるなら、上で書いた簡略化した規則さえ覚えておけばOKです。
変数のスコープ
Cと同様のブロックスコープがあるが、1点だけ違いがある。
{ var x = 1; } var y = x + 1; // ここではxは未定義なのでコンパイルエラー var x = 'x'; // C# では同名の一時変数定義もコンパイルエラー
整数リテラル・浮動小数点数リテラル・10進数リテラル
整数リテラルの後ろにuまたはUをつけると符号なし(Unsigned)、lまたはLをつけるとlong型になる。
同様に、浮動小数点数リテラルの後ろにfまたはFをつけると単精度、dまたはDをつけると倍精度になる。浮動小数点数リテラルは指数表記できる。
小数の後ろにmまたはMをつけると10進数型になる。浮動小数点数型では、2進数で正確に表せない小数が循環小数となってしまう問題がある。それに対して、10進数型では、28桁までの10進数であれば正確な値が保持される。
using System; namespace Sample { class Program { static void Main(string[] args) { var i = 1; var ui = 1U; var l = 1L; var ul = 1UL; var f = 1.0F; var d = 1.0D; var avogadro = 6.02e23; var dec = 1.0M; Console.WriteLine(i.GetType()); // System.Int32 Console.WriteLine(ui.GetType()); // System.UInt32 Console.WriteLine(l.GetType()); // System.Int64 Console.WriteLine(ul.GetType()); // System.UInt64 Console.WriteLine(f.GetType()); // System.Single Console.WriteLine(d.GetType()); // System.Double Console.WriteLine(avogadro.GetType()); // System.Double Console.WriteLine(dec.GetType()); // System.Decimal } } }
文字リテラル・文字列リテラル・逐語的文字列リテラル
char型の値はシングルクォートで囲み、string型の文字列リテラルはダブルクォートで囲む。string型のリテラルのダブルクォートの直前に@をつけると、逐語的文字列リテラル(verbatim string literal)となる。通常のstringは複数行に渡って文字列を定義できないが、逐語的文字列リテラルでは複数行に渡った定義でき、また、エスケープシーケンスが解釈されずそのまま表示される。
using System; namespace Sample { class Program { static void Main(string[] args) { var c = 'c'; var s = "s"; var v = @"varbatim ""string"" // 逐語的文字列リテラル内でダブルクォートを使う場合は2つ連続させる literal"; Console.WriteLine(c.GetType()); // System.Char Console.WriteLine(s.GetType()); // System.String Console.WriteLine(v.GetType()); // System.String } } }
オブジェクト型
オブジェクト型(object)は、全ての型に共通する基底クラス。
匿名型
名前の無い型を定義できる。
var person = new { FamilyName = "Smith", FirstName = "John" };
Console.WriteLine(person.FirstName); // John
Null合体演算子(Null coalescing operator)
string nonNullStr = str != null ? str : "default"; // strがnullの場合は"default"を代入
string nonNullStr = str ?? "default"; // ?? を使うと上の式をシンプルに書ける
型変換
C#では、桁落ちしない、より大きな範囲を扱える型への変換だけが暗黙的に行える。明示的な型変換を行うには、「(変換先の型名)式」という記法を用いる。
オーバーフローのチェック
C#では、オーバーフローを無視するかエラーにするかを選択できる。
checked/uncheckedには式とステートメントの2種類の書き方がある。
↓はcheckedステートメントの例。これを実行すると、オーバーフローが発生した旨の例外が投げられる。
using System; namespace Sample { class Program { static void Main(string[] args) { try { checked { sbyte a = 64; sbyte b = 65; sbyte c = (sbyte)(a + b); // sbyteの上限は128なのでオーバーフロー発生 } } catch (OverflowException ex) { Console.WriteLine(ex.Message); } } } }
以下はunchecked式の例。unchecked式の中で発生したオーバーフローは無視される。
int int1 = unchecked(2147483647 + 10); // -2147483639