using System; using System.Collections; using System.Collections.Generic; namespace RichEnumerables { internal class Program { private static void Main( string[] args ) { IRichEnumerable< IQuestion > questions = new QuestionRepository( ).All( ); IEnumerable< IQuestion > mathQuestions = questions.Where( Is.InCategoryMath( ) ); } } public class QuestionRepository { private IList< IQuestion > questions; public QuestionRepository( ) { questions = new List< IQuestion >( ); questions.Add( new Question( Categories.Math ) ); questions.Add( new Question( Categories.Math ) ); questions.Add( new Question( Categories.Science ) ); questions.Add( new Question( Categories.Math ) ); } public IRichEnumerable< IQuestion > All( ) { return new RichEnumerable< IQuestion >( questions ); } } internal class RichEnumerable< T > : IRichEnumerable< T > { private readonly IEnumerable< T > _items; public RichEnumerable( IEnumerable< T > items ) { _items = items; } public IEnumerable< T > Where( ISpecification< T > criteria ) { foreach( T item in _items ) { if( criteria.IsSatisfiedBy( item ) ) { yield return item; } } } IEnumerator< T > IEnumerable< T >.GetEnumerator( ) { return _items.GetEnumerator( ); } public IEnumerator GetEnumerator( ) { return ( ( IEnumerable< T > )this ).GetEnumerator( ); } } internal class Question : IQuestion { public Question( ICategory category ) { _category = category; } public ICategory Category( ) { return _category; } private readonly ICategory _category; } public interface IRichEnumerable< T > : IEnumerable< T > { IEnumerable< T > Where( ISpecification< T > criteria ); } public interface ISpecification< T > { bool IsSatisfiedBy( T item ); } public interface IQuestion { ICategory Category( ); } public class Is { public static ISpecification< IQuestion > InCategoryMath( ) { return new CategorySpecification( Categories.Math ); } } internal class CategorySpecification : ISpecification< IQuestion > { public CategorySpecification( ICategory category ) { _category = category; } public bool IsSatisfiedBy( IQuestion item ) { return item.Category( ).Equals( _category ); } private readonly ICategory _category; } public interface ICategory {} public class Categories { public static readonly ICategory Math = new Category( "Math" ); public static readonly ICategory Science = new Category( "Science" ); public class Category : ICategory, IEquatable< Category > { public Category( string name ) { _name = name; } public bool Equals( Category category ) { if( category == null ) { return false; } return Equals( _name, category._name ); } public override bool Equals( object obj ) { if( ReferenceEquals( this, obj ) ) { return true; } return Equals( obj as Category ); } public override int GetHashCode( ) { return _name.GetHashCode( ); } private readonly string _name; } } }