I often find in codebases something on the order of if (sprockets.Count() > 0)
which is easily replaced with LINQ's if (sprockets.Any())
. This keeps the entirety of sprockets
from having to be iterated over completely (to get the count) then comparing to zero. Further, the business logic often reads something like "if there are any sprockets, inform the user of the subtotal". I also often see similar logic for exactly one of something: if (sprockets.Count() == 1)
which doesn't have an easy, low-cost LINQ alternative. So I've created one here:
public static bool ExactlyOne<TSource>(this IEnumerable<TSource> source)
{
if (source is null)
{
throw new ArgumentNullException(nameof(source));
}
using (IEnumerator<TSource> enumerator = source.GetEnumerator())
{
return enumerator.MoveNext() && !enumerator.MoveNext();
}
}
Usage is if (sprockets.ExactlyOne())
Here are unit tests. There is one helper method called Infinite()
which is a never-ending enumerable, which will baffle sprockets.Count()
, but not sprockets.ExactlyOne()
:
[TestClass]
public sealed class ExactlyOneTests
{
[TestMethod]
[ExpectedException(typeof(ArgumentNullException))]
public void TestNull()
{
int[] nullArray = null;
Assert.IsFalse(nullArray.ExactlyOne());
}
[TestMethod]
public void TestZero()
{
int[] zero = Array.Empty<int>();
Assert.IsFalse(zero.ExactlyOne());
}
[TestMethod]
public void TestOne()
{
int[] one = { 1 };
Assert.IsTrue(one.ExactlyOne());
}
[TestMethod]
public void TestTwo()
{
int[] two = { 1, 2 };
Assert.IsFalse(two.ExactlyOne());
}
[TestMethod]
public void TestInfinite()
{
IEnumerable<int> infinite = Infinite();
Assert.IsFalse(infinite.ExactlyOne());
}
private static IEnumerable<int> Infinite()
{
while (true)
{
yield return 0;
}
}
}
Looking for overall review - is the code readable, maintainable, performant. Do the tests cover the expected cases or are there more to consider?
SingleOrDefault()
in such cases? OrSingle()
if there has to be a value? \$\endgroup\$ExactlyOne
and it's pretty much what you have: github.com/fsharp/fsharp/blob/… \$\endgroup\$