転職を繰り返したサラリーマンの多趣味ブログ

30才未経験でSEに転職した人の多趣味ブログ

【技術書メモ】C#プログラミングのイディオム / 定石&パターン④

本のタイトルにもなっているイディオム
そもそもイディオムって何だろうと思っていたが、これはコーディングレベルでよく利用される汎用的なコードのこと。
なので、このイディオムを覚えれば、品質もよく、正しいコードを書けることに繋がりそう。特に自分が書いているコードって、思い通りには動くけど、プログラム上級者の人から見たら、どう思われるかいつも心配なので。。

初期化に関するイディオム

変数の宣言と初期化は同時に行うこと。

var age = 25;

配列とリストの初期化

初期化構文を使おう。初期化構文を使うと、要素の入れ替えや追加が楽になるから。

// 配列
var langs = new string[] { "C#", "VB", "C++", };
// リスト
var nums = new List<int> { 10, 20, 30, 40, };

Dictionaryの初期化

こちらも同じく初期化構文を使おう。

// Dictionary
var dict = new Dictionary<string, string>() {
    {"ja", "日本語" },
    {"en", "英語" },
    {"es", "スペイン語" },
    {"de", "ドイツ語" },
};

オブジェクトの初期化

こちらも同じく初期化構文を使用する。オブジェクト生成とプロパティの初期化が同時に行える。

var person = new Person {
    Name = "山田太郎",
    Birthday = new DateTime(1995, 11, 23),
};

初期化構文の特徴として、「要素の入れ替えや追加が容易になる」、「可読性が高まる」といった特徴がある。

判定のイディオム

単純な比較。

// 年齢が10才以下かという人の思考に基づく考え方
if (age <= 10)

数値が範囲内にあるかどうか。

// 数値を直線上に並べた比較
if(MinValue <= num && num <= MaxValue) 

if文の中でのreturn文の使い方。
このように記載すれば、可読性が高まる。

// ふるいにかけて残ったものだけ処理する
if (filePath == null)
    return;
if (GetOption() == Option.Skip)
    return;
// 実行したい処理

繰り返しのイディオム

ループ処理の考え方は、LINQ > foreach > forの順番で適用を考える。
なお、Listクラスの場合だけ、ForEachメソッドを使うと、foreach文よりも簡潔に繰り返し処理が記載できる。

var nums = new List<int> { 1, 2, 3, 4, 5, };
// 12345と出力される
nums.ForEach(n => Console.Write("{0}", n));

条件演算子、null合体演算子によるイディオム

条件演算子

// trueなら1、falseなら0を返却
var num = list.Contains(key) ? 1 : 0;

null合体演算子

// GetMessageがNULLを返却したら、DefaultMessageの値を変数messageにつめる
var message = GetMessage(code) ?? DefaultMessage();

null条件演算子

// sale変数がnullのとき、Productプロパティにアクセスせずにnullを返却する。
// NullPointerExceptionが発生しない
return sale?.Product;

プロパティに関するイディオム

まずは、プロパティの初期化。コンストラクタに初期化処理を書かなくていい。
Javaで慣れている分、プロパティにまだまだ慣れないが。。

// プロパティの初期化
public int MinimumLength { get; set; } = 6;

次が、値を変更できない読み取り専用のプロパティの定義方法。
こう定義すると、外のクラスから値の変更はできなくなる。

public int MinimumLength { get; private set; }

メソッドに関するイディオム

可変長引数。引数の数を限定したくない場合に使用する。
Javaでいうオーバーロードするところを、引数の数の違いだけなら、この書き方で吸収できるというもの。

// 定義
public void WriteInt(params int[] args) {

    foreach(var db in args) {

        Console.WriteLine(db);

    }
}

// 実際の呼び出し方
pp.WriteInt(1, 2, 3, 4, 5);

次にオプション引数。引数を省略した際の初期値を、それぞれ設定できるというもの。

// 定義
public void DoSomething(int num, string message = "失敗しました", int retryCount = 3) {

    Console.WriteLine("{0},{1},{2}",num, message, retryCount);

}

// 実際の呼び出し方
pp.DoSomething(100);
pp.DoSomething(100, "エラーです");
pp.DoSomething(100, "エラーです", 5);

その他のイディオム

ファイルパスの指定には、先頭に@を付加した逐次的リテラル文字列を使用する。
そうすると、¥記号がエスケープ文字として認識されなく、ファイルパスがそのまま記述可能。

var path = @"C:¥Example¥Greeting.txt";

2つの要素を入れ替える。

var temp = a;
a = b;
b = temp;

文字列を数値に変換する。
TryParseメソッドを使用する。エラーハンドリングも行ってくれて、便利!

int height;
if (int.TryParse(str, out height)) {
    // 変換に成功したときの処理
} else {
    // 変換に失敗したときの処理
}