Effective C# 3rd 読書メモ 15 不要なオブジェクトの生成を避ける

GCは効率的に動作するが、それでも無駄なオブジェクトを作りすぎるとパフォーマンス上の悪影響が発生する。
全ての参照型は、ローカル変数であってもメモリ割り当てが行われる。
たとえば、以下のOnPaintメソッドは、PaintイベントのたびにFontのオブジェクトが生成されるため、効率が悪い。

protected override void OnPaint(PaintEventArgs e)
{
    using (Font MyFont = new Font("Arial", 10.0f))
    {
        e.Graphics.DrawString(DateTime.Now.ToString(),
            MyFont, Brushes.Black, new PointF(0, 0));
    }
    base.OnPaint(e);
}

以下のように、インスタンス変数にFontオブジェクトを保持すべきである。

private readonly Font myFont = new Font("Arial", 10.0F);

protected override void OnPaint(PaintEventArgs e)
{
    e.Graphics.DrawString(DateTime.Now.ToString(),
        myFont, Brushes.Black, new PointF(0, 0));
    base.OnPaint(e);
}

一般に、参照型で、頻繁に生成されるローカル変数は、メンバー変数に格上げすべきである。

同様に、頻繁に使用されるインスタンスは、静的プロパティ等の形で取得できるようにすべきである。ここでは、以下のような遅延初期化のテクニックも利用できる。

private static Brush blackBrush;
public static Brush Black
{
    get
    {
        if (blackBrush == null)
            blackBrush = new SolidBrush(Color.Black);
        return blackBrush;
    }
}

最後にもう1つ、イミュータブルな型の変更は避けるべきである。たとえば、C#の文字列はイミュータブルである。文字列に変更を加えると、内部ではSystem.Stringの新しいインスタンスが生成されている。
文字列の組み立てには、補間文字列か、StringBuilderを使用すべきである。

string name = "World";

// (非推奨)+= のたびにインスタンスが作られる
string msg1 = "Hello, ";
msg1 += name;
msg1 += ". Today is ";
msg1 += DateTime.Now.ToString();

// (推奨1)補間文字列の使用
string msg2 = $"Hello {name}. Today is {DateTime.Now.ToString()}";

// (推奨2)StringBuilderの使用
string msg3 = new StringBuilder("Hello, ")
    .Append(name)
    .Append("Today is ")
    .Append(DateTime.Now.ToString())
    .ToString();

補間文字列は、文字列が短い場合や、組み立てに際してロジックがほとんど必要ない場合に適している。
StringBuilderは、文字列が長い場合や、組み立てに際してロジックが必要な場合に適している。

コメントをどうぞ

コメントを残す