Hooked on LINQ

Hooked on LINQ - Developers' Wiki
for .NET Language Integrated Query

Quick Search

Advanced Search »

The Between operator is a sample Sequence operator that returns elements after a StartPredicate has been satisfied, until an End Predicate is satisfied. It is written as a sample and the operator could be implemented in alternative ways using the SkipWhile operator and the TakeWhile operators using a normal query.

The only information we have on the source sequence is that it is IEnumerable (being that is the type our extension method is targeting), so we know we can foreach over the source elements, or manually use our own iteration block.

The code behind this operator shows remarkable similarity to the Sequence.cs source code supplied by Microsoft as part of the MAY 2006 LINQ CTP. This is intentional, the patterns shown in the Standard Query Operators should be the basis for all of our operators to ensure a consistent developer experience when using them. We should throw similar exceptions, and use the delegate prorotypes that all the other operators use.

Back to Writing Operators

Edit

The Code

using System;
using System.Collections.Generic;
using System.Text;
using System.Query;
 
 
namespace Aspiring.Query
{
    public static class BetweenExtensions
    {
        public static IEnumerable<T> Between<T>(
            this IEnumerable<T> source, 
            Func<T, bool> endPredicate) {
 
 
                if (source == null) throw Error.ArgumentNull("source");
                if (endPredicate == null) throw Error.ArgumentNull("endPredicate");
                return BetweenIterator<T>(source, b => true, endPredicate);
        }
 
 
        public static IEnumerable<T> Between<T>(
            this IEnumerable<T> source, 
            Func<T, bool> startPredicate, 
            Func<T, bool> endPredicate) {
 
 
                if (source == null) throw Error.ArgumentNull("source");
                if (startPredicate == null) throw Error.ArgumentNull("startPredicate");
                if (endPredicate == null) throw Error.ArgumentNull("endPredicate");
                return BetweenIterator<T>(source, startPredicate, endPredicate);
        }
 
        
        static IEnumerable<T> BetweenIterator<T>(
            IEnumerable<T> source, 
            Func<T, bool> startPredicate, 
            Func<T, bool> endPredicate) {
 
 
                bool foundStart = false;
 
 
                foreach (T element in source) {
                    if (startPredicate(element))
                        foundStart = true;
 
                    
                    if (foundStart)
                        if (!endPredicate(element)) 
                            yield return element;
                        else
                            yield break;
                }
        }
 
 
        class Error {
            internal static Exception ArgumentNull(string paramName) {
                return new ArgumentNullException(paramName);
            }
        }
    }
}



Edit

The Unit Tests

using System;
using System.Collections.Generic;
using System.Text;
using System.Query;
using NUnit.Framework;
using Aspiring.Query;
 
 
namespace Aspiring.Query.UnitTests
{
    [TestFixture]
    public class BetweenTests
    {
        [Test]
        [ExpectedException("System.ArgumentNullException")]
        public void BetweenEndPredicateNullSourceTest() {
            int[] values = null;
            int[] result = values.Between(end => true).ToArray<int>();
        }
 
 
        [Test]
        [ExpectedException("System.ArgumentNullException")]
        public void BetweenEndPredicateNullPredicateTest() {
            int[] values = null;
            int[] result = values.Between(null).ToArray<int>();
        }
 
 
        [Test]
        [ExpectedException("System.ArgumentNullException")]
        public void BetweenStartAndEndPredicateNullSourceTest() {
            int[] values = null;
            int[] result = values.Between(start => true, end => true).ToArray<int>();
        }
 
 
        [Test]
        [ExpectedException("System.ArgumentNullException")]
        public void BetweenStartAndEndPredicateNullPredicateTest() {
            int[] values = null;
            int[] result = values.Between(null, null).ToArray<int>();
        }
 
 
        [Test]
        public void BetweenStartAndEndIntTest() {
            int[] values = Sequence.Range(0,20).ToArray<int>();
           
            int[] result = values.Between(start => start > 4, end => end > 9).ToArray<int>();
            Assert.AreEqual(5,result.Count(), "incorrect number returned");
 
            for (int i = 0; i < result.Count(); i++)
                Assert.AreEqual(i+5, result[i]);
        }
    }
}



If you would like to comment on this page, click on the Discuss button located on the top-right of each page. Feel free to edit any mistakes or ommissions you find. If you have an objection or find in-appropriate content then contact the administrator. This website is not affiliated with Microsoft®, all content and opinions are those of the specific author and some advice, solutions and article may contain un-intentional errors - please use care. Powered by ScrewTurn Wiki version 2.0.33. Some of the icons created by FamFamFam.