Effective C# 6.0

 

【一休 × bitFlyer】C#を使ったサービス開発の裏側

2017/6/28

宇都宮 諒(@ryo511)

自己紹介

  • 宇都宮 諒(うつのみや りょう)​
  • 株式会社 一休 宿泊事業本部 マーケティング部
  • フロントエンドエンジニア
  • 得意な言語ベスト3
    • PHP, JavaScript, C#
  • 仕事でよく書く言語ベスト3
    • JavaScript, VB.NET, C#

今日はC#の

お話をします

Effective C# 4.0

  • C#を書く上でのベストプラクティスが詰まった名著
  • 全50項目
  • 邦訳はC#4.0版まで(ちょっと古い)

Effective C# 6.0

  • C# 6.0対応!
  • 4.0 => 6.0で、全体の3分の1が入れ替え
  • 原著の出版は2016年12月
  • 未邦訳(2017年6月現在)
  • C# 7.0に対応した『More Effective C#』の第2版も2017年8月に発売予定

(全部は無理なので)

C# 6.0 版で追加された項目を5個紹介します!

※各項目の頭にある数字は

Effective C# 6.0における項目番号です

01. varの使用を推奨する(1)

// こちらでもいいけど
string foo = "foo";

// こっちの方がおすすめ
var foo = "foo";
  • varキーワードによるローカル変数の型推論を使用する

01. varの使用を推奨する(2)

  • 明示的な型指定に起因するバグ
public IEnumerable<string> FindCustomersStartingWith(string start)
    IEnumerable<string> q = from c in db.Customers
                            select c.ContactName;
    var q2 = q.Where(s => s.StartsWith(start));
    return q2;
}
  • ↑のコードはSQLのWHERE句を使って顧客を絞りこむことを想定している
  • しかし、実際には以下のように動作する
    • 1. 全ての顧客のデータをDBから取得
    • 2. Queryable => Enumerableに型変換
    • 3. Enumerable.Where()で絞り込み

01. varの使用を推奨する(3)

  • varによる型推論の活用
public IEnumerable<string> FindCustomersStartingWith(string start)
    var q = from c in db.Customers
            select c.ContactName;
    var q2 = q.Where(s => s.StartsWith(start));
    return q2;
}
  • 1. qにはQueryableが入る
  • 2. Queryable.Where()が実行される
  • 3. WHERE句付きのSQLが実行される

01. varの使用を推奨する(4)

  • 明示的に型指定すべき場合もある
var f = GetMagicnumber();
var total = 10 * f / 6; // totalは6.666... だが、切り捨てられて6になる

int GetMagicNumber()
{
    return 4;
}
double f = GetMagicnumber();
double total = 10 * f / 6;
  • int, double等の数値型は明示的に型を宣言した方が安全

02. 補完文字列を使用する

  • 補完文字列(Interpolated Strings)とは?
var foo = "foo";
var bar = "bar";

// こっちでもいいけど
var sf = string.Format("{0}{1}", foo, bar);

// こっちの方がオススメ
var is = $"{foo}{bar}";

// {}の中には式を書ける
var ex = $"{GetString()}";
  • string.Format()よりも、短く書けて、わかりやすい

06. nameof演算子を使用する

  • ローカル変数の名前を文字列で書いてしまうことがありますよね
public static void DoSomething(object thisCantBeNull)
{
    if (thisCantBeNull == null)
        throw new ArgumentException("thisCantBeNull");
}
  • nameof演算子を使うとローカル変数の名前を取得できます
public static void DoSomething(object thisCantBeNull)
{
    if (thisCantBeNull == null)
        throw new ArgumentException(nameof(thisCantBeNull));
}

08. null条件演算子(1)

  • イベントハンドラの呼び出しをスレッドセーフに書く
public class EventSource
{
    public EventHandler<int> Updated { get; set; }
 
    public void RaiseUpdates()
    {
        _counter++;
        var handler = Updated;
        if (handler != null)
            handler(this, _counter);
 
        // 以下のコードではダメ(スレッドセーフではない)
        // if (Updated != null)
        //     Updated(this, _counter); // Updated がnullになってるかも
    }
 
    private int _counter;
}
  • ちょっと冗長…

08. null条件演算子(2)

  • null条件演算子はスレッドセーフ!
public class EventSource
{
    public EventHandler<int> Updated { get; set; }
 
    public void RaiseUpdates()
    {
        _counter++;
        Updated?.Invoke(this, _counter);
    }
 
    private int _counter;
}

27. yield returnを使う(1)

  • 古典的なコード
public static List<char> GetAlphabetList()
{
    var letter = 'a';
    var charList = new List<char>();
    while (letter >= 'z')
    {
        charList.Add(letter);
        letter++;
    }
    return charList;
}
  • ループが100万回回れば、100万要素のリストが作成されてしまう

27. yield returnを使う(2)

  • yield returnを使う
public static IEnumerable<char> GenerateAlphabet()
{
    var letter = 'a';
    while (letter >= 'z')
    {
        yield return letter;
        letter++;
    }
}
  • 要素が要求されるごとに生成されるので、メモリ効率が良い

まとめ

  • EffectiveなC#を書くための原則
  • 1. 最新の.NET Frameworkを使用する
  • 2. 言語の新機能を使用する
    • 新しい機能は、従来の問題点を修正していることが多い
  • 3. 実行環境のリソース管理を理解する
    • 例外処理はコストが高いとか、ボックス化が発生するとパフォーマンスが低下するとか

ご清聴ありがとう

ございました

Effective C# 6.0

By Ryo Utsunomiya

Effective C# 6.0

【一休 × bitFlyer】C#を使ったサービス開発の裏側(2017/06/28)

  • 2,635