Effective C# 3rd 読書メモ 39 LINQ: FunctionとActionで例外が飛ばないようにする

一連の値に対して処理を行うコードを作成する際に、例外が投げられると、状態の復元に問題が発生する。

以下のようなEmployeeクラスがあるとする。ここでは、MonthlySalaryプロパティのsetterに事前条件のチェックが入っており、例外を投げている。

class Employee
{
    public string Classification { get; set; }

    private int _monthlySalary;

    public int MonthlySalary
    {
        get => _monthlySalary;
        set
        {
            if (Classification != EmployeeType.Active)
                throw new Exception();
            _monthlySalary = value;
        }
    }
}

このクラスに対して、以下のような処理でMonthlySalaryの変更を行おうとすると、例外が発生する可能性がある。また、例外が発生して、途中まで処理が進んでいる場合、状態を復元することは困難である。

var allEmployees = FindAllEmployees();
allEmployees.ForEach(e => e.MonthlySalary *= 1.05M);

この問題に対する最も簡単な解決策は、例外が飛ばないようにすることだ。

allEmployees.FindAll(e => e.Classification == EmployeeType.Active)
            .ForEach(e => e.MonthlySalary *= 1.05M);

しかし、例外が絶対に飛ばないようにできない場合もある。この場合は、処理は一連の要素のコピーに対して行い、全ての処理が成功したらオリジナルと置き換える、という方法がある。

var updates = (from e in allEmployees
               select new Employee
               {
                   Classification = e.Classification,
                   MonthlySalary = e.MonthlySalary * 1.05M,
               }).ToList();
allEmployees = updates;

この方法は、前者よりも実装に手間がかかり、パフォーマンスも劣る。可能であれば前者を使用し、必要な場合にのみ後者を使用すべきである。

コメントをどうぞ

コメントを残す