C#でのクロージャ
クロージャがしっかりと理解しきれていなかったと自覚したのでLearningTestを書いてみた。
まずはテストから。
using System; using System.Collections.Generic; using NUnit.Framework; using NUnit.Framework.SyntaxHelpers; namespace LearningClosure.Tests { [TestFixture] public class ClosureTest { [Test] public void コレクションクロージャメソッドは要素を走査してクロージャを呼び出すべき() { List<Employee> managers = Managers(ObjectMother.CreateEmployees()); Assert.That(managers, Has.Count(2)); Assert.That(List.Map(managers).Property("IsManager"), Is.All.True); } private List<Employee> Managers(List<Employee> employees) { return employees.FindAll(delegate(Employee employee) { return employee.IsManager; }); } [Test] public void クロージャはスコープ外の変数を参照できるべき() { List<Employee> highPaidEmployees = HighPaid(ObjectMother.CreateEmployees()); Assert.That(highPaidEmployees, Has.Count(2)); Assert.That(List.Map(highPaidEmployees).Property("Salary"), Is.All.GreaterThan(150)); } private List<Employee> HighPaid(List<Employee> employees) { int threshold = 150; return employees.FindAll(delegate(Employee employee) { return employee.Salary > threshold; }); } [Test] public void クロージャを返すメソッドでもスコープ外の変数を参照できるべき() { Predicate<Employee> highPaid = PaidMore(150); Employee tsune = new Employee(); tsune.Salary = 200; Assert.That(highPaid(tsune), Is.True); } private Predicate<Employee> PaidMore(int amount) { return delegate(Employee employee) { return employee.Salary > amount; }; } } }
次にシンプルなEmployeeクラス
using System; namespace LearningClosure.Tests { public class Employee { private int salary_; private bool isManager_; public int Salary { get { return salary_; } set { salary_ = value; } } public bool IsManager { get { return isManager_; } set { isManager_ = value; } } } }
最後はObjectMother
using System; using System.Collections.Generic; namespace LearningClosure.Tests { public static class ObjectMother { public static List<Employee> CreateEmployees() { List<Employee> employees = new List<Employee>(); Employee tsune = new Employee(); tsune.Salary = 200; tsune.IsManager = true; employees.Add(tsune); Employee takakuro = new Employee(); takakuro.Salary = 200; takakuro.IsManager = true; employees.Add(takakuro); Employee maru = new Employee(); maru.Salary = 100; employees.Add(maru); Employee che = new Employee(); che.Salary = 100; employees.Add(che); return employees; } } }
このLearningTestを書いている間に、List
このあたりについては、菊池さんの以下の記事を参考にされたい。