一連の値に対して処理を行うコードを作成する際に、例外が投げられると、状態の復元に問題が発生する。
以下のような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;
この方法は、前者よりも実装に手間がかかり、パフォーマンスも劣る。可能であれば前者を使用し、必要な場合にのみ後者を使用すべきである。