表題の話題が挙がったので実験的に。
標準でこういうのない…よね?
アクションの位置をもう少しなんとかしたくはある。
#テスト
EnumerableExTest.cs
[TestClass]
public class MyTestClass
{
[TestMethod]
public void BreakTest()
{
var count = 0;
foreach (var item in new[] { 1, 2, 3 }.BreakWith(() => count++))
{
Console.WriteLine(item);
if (item == 2) break;
}
count.Is(1);
}
[TestMethod]
public void LastBreakTest()
{
var count = 0;
foreach (var item in new[] { 1, 2, 3 }.BreakWith(() => count++))
{
Console.WriteLine(item);
if (item == 3) break;
}
count.Is(1);
}
[TestMethod]
public void NotBreakTest()
{
var count = 0;
foreach (var item in new[] { 1, 2, 3 }.BreakWith(() => count++))
{
Console.WriteLine(item);
}
count.Is(0);
}
[TestMethod, ExpectedException(typeof(ArgumentNullException))]
public void SourceNullTest()
{
((IEnumerable<object>)null).BreakWith(() => { });
}
[TestMethod, ExpectedException(typeof(ArgumentNullException))]
public void ActionNullTest()
{
new[] { new object() }.BreakWith(null);
}
}
#実装
EnumerableEx.cs
public static class EnumerableEx
{
public static IEnumerable<T> BreakWith<T>(this IEnumerable<T> source, Action action)
{
if (source == null) throw new ArgumentNullException("source");
if (action == null) throw new ArgumentNullException("action");
var enumerated = false;
try
{
foreach (var item in source)
{
yield return item;
}
enumerated = true;
}
finally
{
if (!enumerated) action();
}
}
}