// Copyright (c) Microsoft Open Technologies, Inc. All rights reserved. See License.txt in the project root for license information. using System.Collections.Generic; using System.ComponentModel; using System.Globalization; using System.Linq.Expressions; using System.Reflection; namespace System.Linq { /// /// Provides a set of additional static methods that allow querying enumerable sequences. /// public static class QueryableEx { /// /// Determines whether an enumerable sequence is empty. /// /// Source sequence element type. /// Source sequence. /// true if the sequence is empty; false otherwise. public static bool IsEmpty(this IQueryable source) { if (source == null) throw new ArgumentNullException("source"); return source.Provider.Execute( Expression.Call( null, ((MethodInfo)MethodInfo.GetCurrentMethod()).MakeGenericMethod(typeof(TSource)), source.Expression ) ); } #pragma warning disable 1591 [EditorBrowsable(EditorBrowsableState.Never)] public static bool IsEmpty(IEnumerable source) { return EnumerableEx.IsEmpty(source); } #pragma warning restore 1591 /// /// Returns the minimum value in the enumerable sequence by using the specified comparer to compare values. /// /// Source sequence element type. /// Source sequence. /// Comparer used to determine the minimum value. /// Minimum value in the sequence. public static TSource Min(this IQueryable source, IComparer comparer) { if (source == null) throw new ArgumentNullException("source"); if (comparer == null) throw new ArgumentNullException("comparer"); return source.Provider.Execute( Expression.Call( null, ((MethodInfo)MethodInfo.GetCurrentMethod()).MakeGenericMethod(typeof(TSource)), source.Expression, Expression.Constant(comparer, typeof(IComparer)) ) ); } #pragma warning disable 1591 [EditorBrowsable(EditorBrowsableState.Never)] public static TSource Min(IEnumerable source, IComparer comparer) { return EnumerableEx.Min(source, comparer); } #pragma warning restore 1591 /// /// Returns the elements with the minimum key value by using the default comparer to compare key values. /// /// Source sequence element type. /// Key type. /// Source sequence. /// Key selector used to extract the key for each element in the sequence. /// List with the elements that share the same minimum key value. public static IList MinBy(this IQueryable source, Expression> keySelector) { if (source == null) throw new ArgumentNullException("source"); if (keySelector == null) throw new ArgumentNullException("keySelector"); return source.Provider.Execute>( Expression.Call( null, ((MethodInfo)MethodInfo.GetCurrentMethod()).MakeGenericMethod(typeof(TSource), typeof(TKey)), source.Expression, keySelector ) ); } #pragma warning disable 1591 [EditorBrowsable(EditorBrowsableState.Never)] public static IList MinBy(IEnumerable source, Func keySelector) { return EnumerableEx.MinBy(source, keySelector); } #pragma warning restore 1591 /// /// Returns the elements with the minimum key value by using the specified comparer to compare key values. /// /// Source sequence element type. /// Key type. /// Source sequence. /// Key selector used to extract the key for each element in the sequence. /// Comparer used to determine the minimum key value. /// List with the elements that share the same minimum key value. public static IList MinBy(this IQueryable source, Expression> keySelector, IComparer comparer) { if (source == null) throw new ArgumentNullException("source"); if (keySelector == null) throw new ArgumentNullException("keySelector"); if (comparer == null) throw new ArgumentNullException("comparer"); return source.Provider.Execute>( Expression.Call( null, ((MethodInfo)MethodInfo.GetCurrentMethod()).MakeGenericMethod(typeof(TSource), typeof(TKey)), source.Expression, keySelector, Expression.Constant(comparer, typeof(IComparer)) ) ); } #pragma warning disable 1591 [EditorBrowsable(EditorBrowsableState.Never)] public static IList MinBy(IEnumerable source, Func keySelector, IComparer comparer) { return EnumerableEx.MinBy(source, keySelector, comparer); } #pragma warning restore 1591 /// /// Returns the maximum value in the enumerable sequence by using the specified comparer to compare values. /// /// Source sequence element type. /// Source sequence. /// Comparer used to determine the maximum value. /// Maximum value in the sequence. public static TSource Max(this IQueryable source, IComparer comparer) { if (source == null) throw new ArgumentNullException("source"); if (comparer == null) throw new ArgumentNullException("comparer"); return source.Provider.Execute( Expression.Call( null, ((MethodInfo)MethodInfo.GetCurrentMethod()).MakeGenericMethod(typeof(TSource)), source.Expression, Expression.Constant(comparer, typeof(IComparer)) ) ); } #pragma warning disable 1591 [EditorBrowsable(EditorBrowsableState.Never)] public static TSource Max(IEnumerable source, IComparer comparer) { return EnumerableEx.Max(source, comparer); } #pragma warning restore 1591 /// /// Returns the elements with the maximum key value by using the default comparer to compare key values. /// /// Source sequence element type. /// Key type. /// Source sequence. /// Key selector used to extract the key for each element in the sequence. /// List with the elements that share the same maximum key value. public static IList MaxBy(this IQueryable source, Expression> keySelector) { if (source == null) throw new ArgumentNullException("source"); if (keySelector == null) throw new ArgumentNullException("keySelector"); return source.Provider.Execute>( Expression.Call( null, ((MethodInfo)MethodInfo.GetCurrentMethod()).MakeGenericMethod(typeof(TSource), typeof(TKey)), source.Expression, keySelector ) ); } #pragma warning disable 1591 [EditorBrowsable(EditorBrowsableState.Never)] public static IList MaxBy(IEnumerable source, Func keySelector) { return EnumerableEx.MaxBy(source, keySelector); } #pragma warning restore 1591 /// /// Returns the elements with the minimum key value by using the specified comparer to compare key values. /// /// Source sequence element type. /// Key type. /// Source sequence. /// Key selector used to extract the key for each element in the sequence. /// Comparer used to determine the maximum key value. /// List with the elements that share the same maximum key value. public static IList MaxBy(this IQueryable source, Expression> keySelector, IComparer comparer) { if (source == null) throw new ArgumentNullException("source"); if (keySelector == null) throw new ArgumentNullException("keySelector"); if (comparer == null) throw new ArgumentNullException("comparer"); return source.Provider.Execute>( Expression.Call( null, ((MethodInfo)MethodInfo.GetCurrentMethod()).MakeGenericMethod(typeof(TSource), typeof(TKey)), source.Expression, keySelector, Expression.Constant(comparer, typeof(IComparer)) ) ); } #pragma warning disable 1591 [EditorBrowsable(EditorBrowsableState.Never)] public static IList MaxBy(IEnumerable source, Func keySelector, IComparer comparer) { return EnumerableEx.MaxBy(source, keySelector, comparer); } #pragma warning restore 1591 /// /// Shares the source sequence within a selector function where each enumerator can fetch the next element from the source sequence. /// /// Source sequence element type. /// Result sequence element type. /// Source sequence. /// Selector function with shared access to the source sequence for each enumerator. /// Sequence resulting from applying the selector function to the shared view over the source sequence. public static IQueryable Share(this IQueryable source, Expression, IEnumerable>> selector) { if (source == null) throw new ArgumentNullException("source"); if (selector == null) throw new ArgumentNullException("selector"); return source.Provider.CreateQuery( Expression.Call( null, ((MethodInfo)MethodInfo.GetCurrentMethod()).MakeGenericMethod(typeof(TSource), typeof(TResult)), source.Expression, selector ) ); } #pragma warning disable 1591 [EditorBrowsable(EditorBrowsableState.Never)] public static IEnumerable Share(IEnumerable source, Func, IEnumerable> selector) { return EnumerableEx.Share(source, selector); } #pragma warning restore 1591 /// /// Publishes the source sequence within a selector function where each enumerator can obtain a view over a tail of the source sequence. /// /// Source sequence element type. /// Result sequence element type. /// Source sequence. /// Selector function with published access to the source sequence for each enumerator. /// Sequence resulting from applying the selector function to the published view over the source sequence. public static IQueryable Publish(this IQueryable source, Expression, IEnumerable>> selector) { if (source == null) throw new ArgumentNullException("source"); if (selector == null) throw new ArgumentNullException("selector"); return source.Provider.CreateQuery( Expression.Call( null, ((MethodInfo)MethodInfo.GetCurrentMethod()).MakeGenericMethod(typeof(TSource), typeof(TResult)), source.Expression, selector ) ); } #pragma warning disable 1591 [EditorBrowsable(EditorBrowsableState.Never)] public static IEnumerable Publish(IEnumerable source, Func, IEnumerable> selector) { return EnumerableEx.Publish(source, selector); } #pragma warning restore 1591 /// /// Memoizes the source sequence within a selector function where each enumerator can get access to all of the sequence's elements without causing multiple enumerations over the source. /// /// Source sequence element type. /// Result sequence element type. /// Source sequence. /// Selector function with memoized access to the source sequence for each enumerator. /// Sequence resulting from applying the selector function to the memoized view over the source sequence. public static IQueryable Memoize(this IQueryable source, Expression, IEnumerable>> selector) { if (source == null) throw new ArgumentNullException("source"); if (selector == null) throw new ArgumentNullException("selector"); return source.Provider.CreateQuery( Expression.Call( null, ((MethodInfo)MethodInfo.GetCurrentMethod()).MakeGenericMethod(typeof(TSource), typeof(TResult)), source.Expression, selector ) ); } #pragma warning disable 1591 [EditorBrowsable(EditorBrowsableState.Never)] public static IEnumerable Memoize(IEnumerable source, Func, IEnumerable> selector) { return EnumerableEx.Memoize(source, selector); } #pragma warning restore 1591 /// /// Memoizes the source sequence within a selector function where a specified number of enumerators can get access to all of the sequence's elements without causing multiple enumerations over the source. /// /// Source sequence element type. /// Result sequence element type. /// Source sequence. /// Number of enumerators that can access the underlying buffer. Once every enumerator has obtained an element from the buffer, the element is removed from the buffer. /// Selector function with memoized access to the source sequence for a specified number of enumerators. /// Sequence resulting from applying the selector function to the memoized view over the source sequence. public static IQueryable Memoize(this IQueryable source, int readerCount, Expression, IEnumerable>> selector) { if (source == null) throw new ArgumentNullException("source"); if (selector == null) throw new ArgumentNullException("selector"); return source.Provider.CreateQuery( Expression.Call( null, ((MethodInfo)MethodInfo.GetCurrentMethod()).MakeGenericMethod(typeof(TSource), typeof(TResult)), source.Expression, Expression.Constant(readerCount, typeof(int)), selector ) ); } #pragma warning disable 1591 [EditorBrowsable(EditorBrowsableState.Never)] public static IEnumerable Memoize(IEnumerable source, int readerCount, Func, IEnumerable> selector) { return EnumerableEx.Memoize(source, readerCount, selector); } #pragma warning restore 1591 /// /// Creates an enumerable sequence based on an enumerator factory function. /// /// Result sequence element type. /// Query provider. /// Enumerator factory function. /// Sequence that will invoke the enumerator factory upon a call to GetEnumerator. public static IQueryable Create(this IQueryProvider provider, Expression>> getEnumerator) { if (provider == null) throw new ArgumentNullException("provider"); if (getEnumerator == null) throw new ArgumentNullException("getEnumerator"); return provider.CreateQuery( Expression.Call( null, ((MethodInfo)MethodInfo.GetCurrentMethod()).MakeGenericMethod(typeof(TResult)), Expression.Constant(provider, typeof(IQueryProvider)), getEnumerator ) ); } #pragma warning disable 1591 [EditorBrowsable(EditorBrowsableState.Never)] public static IEnumerable Create(Func> getEnumerator) { return EnumerableEx.Create(getEnumerator); } #pragma warning restore 1591 /// /// Returns a sequence with a single element. /// /// Result sequence element type. /// Query provider. /// Single element of the resulting sequence. /// Sequence with a single element. public static IQueryable Return(this IQueryProvider provider, TResult value) { if (provider == null) throw new ArgumentNullException("provider"); return provider.CreateQuery( Expression.Call( null, ((MethodInfo)MethodInfo.GetCurrentMethod()).MakeGenericMethod(typeof(TResult)), Expression.Constant(provider, typeof(IQueryProvider)), Expression.Constant(value, typeof(TResult)) ) ); } #pragma warning disable 1591 [EditorBrowsable(EditorBrowsableState.Never)] public static /*!*/IQueryable Return(TResult value) { return EnumerableEx.Return(value).AsQueryable(); } #pragma warning restore 1591 /// /// Returns a sequence that throws an exception upon enumeration. /// /// Result sequence element type. /// Query provider. /// Exception to throw upon enumerating the resulting sequence. /// Sequence that throws the specified exception upon enumeration. public static IQueryable Throw(this IQueryProvider provider, Exception exception) { if (provider == null) throw new ArgumentNullException("provider"); if (exception == null) throw new ArgumentNullException("exception"); return provider.CreateQuery( Expression.Call( null, ((MethodInfo)MethodInfo.GetCurrentMethod()).MakeGenericMethod(typeof(TResult)), Expression.Constant(provider, typeof(IQueryProvider)), Expression.Constant(exception, typeof(Exception)) ) ); } #pragma warning disable 1591 [EditorBrowsable(EditorBrowsableState.Never)] public static /*!*/IQueryable Throw(Exception exception) { return EnumerableEx.Throw(exception).AsQueryable(); } #pragma warning restore 1591 /// /// Creates an enumerable sequence based on an enumerable factory function. /// /// Result sequence element type. /// Query provider. /// Enumerable factory function. /// Sequence that will invoke the enumerable factory upon a call to GetEnumerator. public static IQueryable Defer(this IQueryProvider provider, Expression>> enumerableFactory) { if (provider == null) throw new ArgumentNullException("provider"); if (enumerableFactory == null) throw new ArgumentNullException("enumerableFactory"); return provider.CreateQuery( Expression.Call( null, ((MethodInfo)MethodInfo.GetCurrentMethod()).MakeGenericMethod(typeof(TResult)), Expression.Constant(provider, typeof(IQueryProvider)), enumerableFactory ) ); } #pragma warning disable 1591 [EditorBrowsable(EditorBrowsableState.Never)] public static /*!*/IQueryable Defer(Func> enumerableFactory) { return EnumerableEx.Defer(enumerableFactory).AsQueryable(); } #pragma warning restore 1591 /// /// Generates a sequence by mimicking a for loop. /// /// State type. /// Result sequence element type. /// Query provider. /// Initial state of the generator loop. /// Loop condition. /// State update function to run after every iteration of the generator loop. /// Result selector to compute resulting sequence elements. /// Sequence obtained by running the generator loop, yielding computed elements. public static IQueryable Generate(this IQueryProvider provider, TState initialState, Expression> condition, Expression> iterate, Expression> resultSelector) { if (provider == null) throw new ArgumentNullException("provider"); if (condition == null) throw new ArgumentNullException("condition"); if (iterate == null) throw new ArgumentNullException("iterate"); if (resultSelector == null) throw new ArgumentNullException("resultSelector"); return provider.CreateQuery( Expression.Call( null, ((MethodInfo)MethodInfo.GetCurrentMethod()).MakeGenericMethod(typeof(TState), typeof(TResult)), Expression.Constant(provider, typeof(IQueryProvider)), Expression.Constant(initialState), condition, iterate, resultSelector ) ); } #pragma warning disable 1591 [EditorBrowsable(EditorBrowsableState.Never)] public static /*!*/IQueryable Generate(TState initialState, Func condition, Func iterate, Func resultSelector) { return EnumerableEx.Generate(initialState, condition, iterate, resultSelector).AsQueryable(); } #pragma warning restore 1591 /// /// Generates a sequence that's dependent on a resource object whose lifetime is determined by the sequence usage duration. /// /// Source element type. /// Resource type. /// Query provider. /// Resource factory function. /// Enumerable factory function, having access to the obtained resource. /// Sequence whose use controls the lifetime of the associated obtained resource. public static IQueryable Using(this IQueryProvider provider, Expression> resourceFactory, Expression>> enumerableFactory) where TResource : IDisposable { if (provider == null) throw new ArgumentNullException("provider"); if (resourceFactory == null) throw new ArgumentNullException("resourceFactory"); if (enumerableFactory == null) throw new ArgumentNullException("enumerableFactory"); return provider.CreateQuery( Expression.Call( null, ((MethodInfo)MethodInfo.GetCurrentMethod()).MakeGenericMethod(typeof(TSource), typeof(TResource)), Expression.Constant(provider, typeof(IQueryProvider)), resourceFactory, enumerableFactory ) ); } #pragma warning disable 1591 [EditorBrowsable(EditorBrowsableState.Never)] public static /*!*/IQueryable Using(Func resourceFactory, Func> enumerableFactory) where TResource : IDisposable { return EnumerableEx.Using(resourceFactory, enumerableFactory).AsQueryable(); } #pragma warning restore 1591 /// /// Generates a sequence by repeating the given value infinitely. /// /// Result sequence element type. /// Query provider. /// Value to repreat in the resulting sequence. /// Sequence repeating the given value infinitely. public static IEnumerable Repeat(this IQueryProvider provider, TResult value) { if (provider == null) throw new ArgumentNullException("provider"); return provider.CreateQuery( Expression.Call( null, ((MethodInfo)MethodInfo.GetCurrentMethod()).MakeGenericMethod(typeof(TResult)), Expression.Constant(provider, typeof(IQueryProvider)), Expression.Constant(value, typeof(TResult)) ) ); } #pragma warning disable 1591 [EditorBrowsable(EditorBrowsableState.Never)] public static /*!*/IQueryable Repeat(TResult value) { return EnumerableEx.Repeat(value).AsQueryable(); } #pragma warning restore 1591 /// /// Creates a sequence that corresponds to the source sequence, concatenating it with the sequence resulting from calling an exception handler function in case of an error. /// /// Source sequence element type. /// Exception type to catch. /// Source sequence. /// Handler to invoke when an exception of the specified type occurs. /// Source sequence, concatenated with an exception handler result sequence in case of an error. public static IQueryable Catch(this IQueryable source, Expression>> handler) where TException : Exception { if (source == null) throw new ArgumentNullException("source"); if (handler == null) throw new ArgumentNullException("handler"); return source.Provider.CreateQuery( Expression.Call( null, ((MethodInfo)MethodInfo.GetCurrentMethod()).MakeGenericMethod(typeof(TSource), typeof(TException)), source.Expression, handler ) ); } #pragma warning disable 1591 [EditorBrowsable(EditorBrowsableState.Never)] public static IEnumerable Catch(IEnumerable source, Func> handler) where TException : Exception { return EnumerableEx.Catch(source, handler); } #pragma warning restore 1591 /// /// Creates a sequence by concatenating source sequences until a source sequence completes successfully. /// /// Source sequence element type. /// Source sequences. /// Sequence that continues to concatenate source sequences while errors occur. public static IQueryable Catch(this IQueryable> sources) { if (sources == null) throw new ArgumentNullException("sources"); return sources.Provider.CreateQuery( Expression.Call( null, ((MethodInfo)MethodInfo.GetCurrentMethod()).MakeGenericMethod(typeof(TSource)), sources.Expression ) ); } #pragma warning disable 1591 [EditorBrowsable(EditorBrowsableState.Never)] public static IEnumerable Catch(IEnumerable> sources) { return EnumerableEx.Catch(sources); } #pragma warning restore 1591 /// /// Creates a sequence by concatenating source sequences until a source sequence completes successfully. /// /// Source sequence element type. /// Query provider. /// Source sequences. /// Sequence that continues to concatenate source sequences while errors occur. public static IQueryable Catch(this IQueryProvider provider, params IEnumerable[] sources) { if (provider == null) throw new ArgumentNullException("provider"); if (sources == null) throw new ArgumentNullException("sources"); return provider.CreateQuery( Expression.Call( null, ((MethodInfo)MethodInfo.GetCurrentMethod()).MakeGenericMethod(typeof(TSource)), Expression.Constant(provider, typeof(IQueryProvider)), GetSourceExpression(sources) ) ); } #pragma warning disable 1591 [EditorBrowsable(EditorBrowsableState.Never)] public static /*!*/IQueryable Catch(params IEnumerable[] sources) { return EnumerableEx.Catch(sources).AsQueryable(); } #pragma warning restore 1591 /// /// Creates a sequence that returns the elements of the first sequence, switching to the second in case of an error. /// /// Source sequence element type. /// First sequence. /// Second sequence, concatenated to the result in case the first sequence completes exceptionally. /// The first sequence, followed by the second sequence in case an error is produced. public static IQueryable Catch(this IQueryable first, IEnumerable second) { if (first == null) throw new ArgumentNullException("first"); if (second == null) throw new ArgumentNullException("second"); return first.Provider.CreateQuery( Expression.Call( null, ((MethodInfo)MethodInfo.GetCurrentMethod()).MakeGenericMethod(typeof(TSource)), first.Expression, GetSourceExpression(second) ) ); } #pragma warning disable 1591 [EditorBrowsable(EditorBrowsableState.Never)] public static IEnumerable Catch(IEnumerable first, IEnumerable second) { return EnumerableEx.Catch(first, second); } #pragma warning restore 1591 /// /// Creates a sequence whose termination or disposal of an enumerator causes a finally action to be executed. /// /// Source sequence element type. /// Source sequence. /// Action to run upon termination of the sequence, or when an enumerator is disposed. /// Source sequence with guarantees on the invocation of the finally action. public static IQueryable Finally(this IQueryable source, Expression finallyAction) { if (source == null) throw new ArgumentNullException("source"); if (finallyAction == null) throw new ArgumentNullException("finallyAction"); return source.Provider.CreateQuery( Expression.Call( null, ((MethodInfo)MethodInfo.GetCurrentMethod()).MakeGenericMethod(typeof(TSource)), source.Expression, finallyAction ) ); } #pragma warning disable 1591 [EditorBrowsable(EditorBrowsableState.Never)] public static IEnumerable Finally(IEnumerable source, Action finallyAction) { return EnumerableEx.Finally(source, finallyAction); } #pragma warning restore 1591 /// /// Creates a sequence that concatenates both given sequences, regardless of whether an error occurs. /// /// Source sequence element type. /// First sequence. /// Second sequence. /// Sequence concatenating the elements of both sequences, ignoring errors. public static IQueryable OnErrorResumeNext(this IQueryable first, IEnumerable second) { if (first == null) throw new ArgumentNullException("first"); if (second == null) throw new ArgumentNullException("second"); return first.Provider.CreateQuery( Expression.Call( null, ((MethodInfo)MethodInfo.GetCurrentMethod()).MakeGenericMethod(typeof(TSource)), first.Expression, GetSourceExpression(second) ) ); } #pragma warning disable 1591 [EditorBrowsable(EditorBrowsableState.Never)] public static IEnumerable OnErrorResumeNext(IEnumerable first, IEnumerable second) { return EnumerableEx.OnErrorResumeNext(first, second); } #pragma warning restore 1591 /// /// Creates a sequence that concatenates the given sequences, regardless of whether an error occurs in any of the sequences. /// /// Source sequence element type. /// Query provider. /// Source sequences. /// Sequence concatenating the elements of the given sequences, ignoring errors. public static IEnumerable OnErrorResumeNext(this IQueryProvider provider, params IEnumerable[] sources) { if (provider == null) throw new ArgumentNullException("provider"); if (sources == null) throw new ArgumentNullException("sources"); return provider.CreateQuery( Expression.Call( null, ((MethodInfo)MethodInfo.GetCurrentMethod()).MakeGenericMethod(typeof(TSource)), Expression.Constant(provider, typeof(IQueryProvider)), GetSourceExpression(sources) ) ); } #pragma warning disable 1591 [EditorBrowsable(EditorBrowsableState.Never)] public static /*!*/IQueryable OnErrorResumeNext(params IEnumerable[] sources) { return EnumerableEx.OnErrorResumeNext(sources).AsQueryable(); } #pragma warning restore 1591 /// /// Creates a sequence that concatenates the given sequences, regardless of whether an error occurs in any of the sequences. /// /// Source sequence element type. /// Source sequences. /// Sequence concatenating the elements of the given sequences, ignoring errors. public static IQueryable OnErrorResumeNext(this IQueryable> sources) { if (sources == null) throw new ArgumentNullException("sources"); return sources.Provider.CreateQuery( Expression.Call( null, ((MethodInfo)MethodInfo.GetCurrentMethod()).MakeGenericMethod(typeof(TSource)), sources.Expression ) ); } #pragma warning disable 1591 [EditorBrowsable(EditorBrowsableState.Never)] public static IEnumerable OnErrorResumeNext(IEnumerable> sources) { return EnumerableEx.OnErrorResumeNext(sources); } #pragma warning restore 1591 /// /// Creates a sequence that retries enumerating the source sequence as long as an error occurs. /// /// Source sequence element type. /// Source sequence. /// Sequence concatenating the results of the source sequence as long as an error occurs. public static IQueryable Retry(this IQueryable source) { if (source == null) throw new ArgumentNullException("source"); return source.Provider.CreateQuery( Expression.Call( null, ((MethodInfo)MethodInfo.GetCurrentMethod()).MakeGenericMethod(typeof(TSource)), source.Expression ) ); } #pragma warning disable 1591 [EditorBrowsable(EditorBrowsableState.Never)] public static IEnumerable Retry(IEnumerable source) { return EnumerableEx.Retry(source); } #pragma warning restore 1591 /// /// Creates a sequence that retries enumerating the source sequence as long as an error occurs, with the specified maximum number of retries. /// /// Source sequence element type. /// Source sequence. /// Maximum number of retries. /// Sequence concatenating the results of the source sequence as long as an error occurs. public static IQueryable Retry(this IQueryable source, int retryCount) { if (source == null) throw new ArgumentNullException("source"); return source.Provider.CreateQuery( Expression.Call( null, ((MethodInfo)MethodInfo.GetCurrentMethod()).MakeGenericMethod(typeof(TSource)), source.Expression, Expression.Constant(retryCount, typeof(int)) ) ); } #pragma warning disable 1591 [EditorBrowsable(EditorBrowsableState.Never)] public static IEnumerable Retry(IEnumerable source, int retryCount) { return EnumerableEx.Retry(source, retryCount); } #pragma warning restore 1591 /// /// Generates an enumerable sequence by repeating a source sequence as long as the given loop condition holds. /// /// Result sequence element type. /// Query provider. /// Loop condition. /// Sequence to repeat while the condition evaluates true. /// Sequence generated by repeating the given sequence while the condition evaluates to true. public static IQueryable While(this IQueryProvider provider, Expression> condition, IEnumerable source) { if (provider == null) throw new ArgumentNullException("provider"); if (condition == null) throw new ArgumentNullException("condition"); if (source == null) throw new ArgumentNullException("source"); return provider.CreateQuery( Expression.Call( null, ((MethodInfo)MethodInfo.GetCurrentMethod()).MakeGenericMethod(typeof(TResult)), Expression.Constant(provider, typeof(IQueryProvider)), condition, GetSourceExpression(source) ) ); } #pragma warning disable 1591 [EditorBrowsable(EditorBrowsableState.Never)] public static /*!*/IQueryable While(Func condition, IEnumerable source) { return EnumerableEx.While(condition, source).AsQueryable(); } #pragma warning restore 1591 /// /// Returns an enumerable sequence based on the evaluation result of the given condition. /// /// Result sequence element type. /// Query provider. /// Condition to evaluate. /// Sequence to return in case the condition evaluates true. /// Sequence to return in case the condition evaluates false. /// Either of the two input sequences based on the result of evaluating the condition. public static IQueryable If(this IQueryProvider provider, Expression> condition, IEnumerable thenSource, IEnumerable elseSource) { if (provider == null) throw new ArgumentNullException("provider"); if (condition == null) throw new ArgumentNullException("condition"); if (thenSource == null) throw new ArgumentNullException("thenSource"); if (elseSource == null) throw new ArgumentNullException("elseSource"); return provider.CreateQuery( Expression.Call( null, ((MethodInfo)MethodInfo.GetCurrentMethod()).MakeGenericMethod(typeof(TResult)), Expression.Constant(provider, typeof(IQueryProvider)), condition, GetSourceExpression(thenSource), GetSourceExpression(elseSource) ) ); } #pragma warning disable 1591 [EditorBrowsable(EditorBrowsableState.Never)] public static /*!*/IQueryable If(Func condition, IEnumerable thenSource, IEnumerable elseSource) { return EnumerableEx.If(condition, thenSource, elseSource).AsQueryable(); } #pragma warning restore 1591 /// /// Returns an enumerable sequence if the evaluation result of the given condition is true, otherwise returns an empty sequence. /// /// Result sequence element type. /// Query provider. /// Condition to evaluate. /// Sequence to return in case the condition evaluates true. /// The given input sequence if the condition evaluates true; otherwise, an empty sequence. public static IQueryable If(this IQueryProvider provider, Expression> condition, IEnumerable thenSource) { if (provider == null) throw new ArgumentNullException("provider"); if (condition == null) throw new ArgumentNullException("condition"); if (thenSource == null) throw new ArgumentNullException("thenSource"); return provider.CreateQuery( Expression.Call( null, ((MethodInfo)MethodInfo.GetCurrentMethod()).MakeGenericMethod(typeof(TResult)), Expression.Constant(provider, typeof(IQueryProvider)), condition, GetSourceExpression(thenSource) ) ); } #pragma warning disable 1591 [EditorBrowsable(EditorBrowsableState.Never)] public static /*!*/IQueryable If(Func condition, IEnumerable thenSource) { return EnumerableEx.If(condition, thenSource).AsQueryable(); } #pragma warning restore 1591 /// /// Generates an enumerable sequence by repeating a source sequence as long as the given loop postcondition holds. /// /// Result sequence element type. /// Source sequence to repeat while the condition evaluates true. /// Loop condition. /// Sequence generated by repeating the given sequence until the condition evaluates to false. public static IQueryable DoWhile(this IQueryable source, Expression> condition) { if (source == null) throw new ArgumentNullException("source"); if (condition == null) throw new ArgumentNullException("condition"); return source.Provider.CreateQuery( Expression.Call( null, ((MethodInfo)MethodInfo.GetCurrentMethod()).MakeGenericMethod(typeof(TResult)), source.Expression, condition ) ); } #pragma warning disable 1591 [EditorBrowsable(EditorBrowsableState.Never)] public static IEnumerable DoWhile(IEnumerable source, Func condition) { return EnumerableEx.DoWhile(source, condition); } #pragma warning restore 1591 /// /// Returns a sequence from a dictionary based on the result of evaluating a selector function. /// /// Type of the selector value. /// Result sequence element type. /// Query provider. /// Selector function used to pick a sequence from the given sources. /// Dictionary mapping selector values onto resulting sequences. /// The source sequence corresponding with the evaluated selector value; otherwise, an empty sequence. public static IQueryable Case(this IQueryProvider provider, Expression> selector, IDictionary> sources) { if (provider == null) throw new ArgumentNullException("provider"); if (selector == null) throw new ArgumentNullException("selector"); if (sources == null) throw new ArgumentNullException("sources"); return provider.CreateQuery( Expression.Call( null, ((MethodInfo)MethodInfo.GetCurrentMethod()).MakeGenericMethod(typeof(TValue), typeof(TResult)), selector, Expression.Constant(sources, typeof(IDictionary>)) ) ); } #pragma warning disable 1591 [EditorBrowsable(EditorBrowsableState.Never)] public static /*!*/IQueryable Case(Func selector, IDictionary> sources) { return EnumerableEx.Case(selector, sources).AsQueryable(); } #pragma warning restore 1591 /// /// Returns a sequence from a dictionary based on the result of evaluating a selector function, also specifying a default sequence. /// /// Type of the selector value. /// Result sequence element type. /// Query provider. /// Selector function used to pick a sequence from the given sources. /// Dictionary mapping selector values onto resulting sequences. /// Default sequence to return in case there's no corresponding source for the computed selector value. /// The source sequence corresponding with the evaluated selector value; otherwise, the default source. public static IQueryable Case(this IQueryProvider provider, Expression> selector, IDictionary> sources, IEnumerable defaultSource) { if (provider == null) throw new ArgumentNullException("provider"); if (selector == null) throw new ArgumentNullException("selector"); if (sources == null) throw new ArgumentNullException("sources"); if (defaultSource == null) throw new ArgumentNullException("defaultSource"); return provider.CreateQuery( Expression.Call( null, ((MethodInfo)MethodInfo.GetCurrentMethod()).MakeGenericMethod(typeof(TValue), typeof(TResult)), selector, Expression.Constant(sources, typeof(IDictionary>)) ) ); } #pragma warning disable 1591 [EditorBrowsable(EditorBrowsableState.Never)] public static /*!*/IQueryable Case(Func selector, IDictionary> sources, IEnumerable defaultSource) { return EnumerableEx.Case(selector, sources, defaultSource).AsQueryable(); } #pragma warning restore 1591 /// /// Generates a sequence by enumerating a source sequence, mapping its elements on result sequences, and concatenating those sequences. /// /// Source sequence element type. /// Result sequence element type. /// Query provider. /// Source sequence. /// Result selector to evaluate for each iteration over the source. /// Sequence concatenating the inner sequences that result from evaluating the result selector on elements from the source. public static IQueryable For(this IQueryProvider provider, IEnumerable source, Expression>> resultSelector) { if (provider == null) throw new ArgumentNullException("provider"); if (source == null) throw new ArgumentNullException("source"); if (resultSelector == null) throw new ArgumentNullException("resultSelector"); return provider.CreateQuery( Expression.Call( null, ((MethodInfo)MethodInfo.GetCurrentMethod()).MakeGenericMethod(typeof(TSource), typeof(TResult)), GetSourceExpression(source), resultSelector ) ); } #pragma warning disable 1591 [EditorBrowsable(EditorBrowsableState.Never)] public static /*!*/IQueryable For(IEnumerable source, Func> resultSelector) { return EnumerableEx.For(source, resultSelector).AsQueryable(); } #pragma warning restore 1591 /// /// Concatenates the input sequences. /// /// Source sequence element type. /// Source sequences. /// Sequence with the elements of the source sequences concatenated. public static IQueryable Concat(this IQueryable> sources) { if (sources == null) throw new ArgumentNullException("sources"); return sources.Provider.CreateQuery( Expression.Call( null, ((MethodInfo)MethodInfo.GetCurrentMethod()).MakeGenericMethod(typeof(TSource)), GetSourceExpression(sources) ) ); } #pragma warning disable 1591 [EditorBrowsable(EditorBrowsableState.Never)] public static IEnumerable Concat(IEnumerable> sources) { return EnumerableEx.Concat(sources); } #pragma warning restore 1591 /// /// Concatenates the input sequences. /// /// Source sequence element type. /// Query provider. /// Source sequences. /// Sequence with the elements of the source sequences concatenated. public static IQueryable Concat(this IQueryProvider provider, params IEnumerable[] sources) { if (provider == null) throw new ArgumentNullException("provider"); if (sources == null) throw new ArgumentNullException("sources"); return provider.CreateQuery( Expression.Call( null, ((MethodInfo)MethodInfo.GetCurrentMethod()).MakeGenericMethod(typeof(TSource)), Expression.Constant(provider, typeof(IQueryProvider)), GetSourceExpression(sources) ) ); } #pragma warning disable 1591 [EditorBrowsable(EditorBrowsableState.Never)] public static /*!*/IQueryable Concat(params IEnumerable[] sources) { return EnumerableEx.Concat(sources).AsQueryable(); } #pragma warning restore 1591 /// /// Projects each element of a sequence to an given sequence and flattens the resulting sequences into one sequence. /// /// First source sequence element type. /// Second source sequence element type. /// A sequence of values to project. /// Inner sequence each source sequenec element is projected onto. /// Sequence flattening the sequences that result from projecting elements in the source sequence. public static IQueryable SelectMany(this IQueryable source, IEnumerable other) { if (source == null) throw new ArgumentNullException("source"); if (other == null) throw new ArgumentNullException("other"); return source.Provider.CreateQuery( Expression.Call( null, ((MethodInfo)MethodInfo.GetCurrentMethod()).MakeGenericMethod(typeof(TSource), typeof(TOther)), source.Expression, GetSourceExpression(other) ) ); } #pragma warning disable 1591 [EditorBrowsable(EditorBrowsableState.Never)] public static IEnumerable SelectMany(IEnumerable source, IEnumerable other) { return EnumerableEx.SelectMany(source, other); } #pragma warning restore 1591 #if NO_ZIP /// /// Merges two sequences by applying the specified selector function on index-based corresponding element pairs from both sequences. /// /// The type of the elements of the first input sequence. /// The type of the elements of the second input sequence. /// The type of the elements of the result sequence. /// The first sequence to merge. /// The second sequence to merge. /// Function to apply to each pair of elements from both sequences. /// Sequence consisting of the result of pairwise application of the selector function over pairs of elements from the source sequences. public static IQueryable Zip(this IQueryable first, IEnumerable second, Expression> resultSelector) { if (first == null) throw new ArgumentNullException("first"); if (second == null) throw new ArgumentNullException("second"); if (resultSelector == null) throw new ArgumentNullException("resultSelector"); return first.Provider.CreateQuery( Expression.Call( null, ((MethodInfo)MethodInfo.GetCurrentMethod()).MakeGenericMethod(typeof(TFirst), typeof(TSecond), typeof(TResult)), first.Expression, GetSourceExpression(second), resultSelector ) ); } #pragma warning disable 1591 [EditorBrowsable(EditorBrowsableState.Never)] public static IEnumerable Zip(IEnumerable first, IEnumerable second, Func resultSelector) { return EnumerableEx.Zip(first, second, resultSelector); } #pragma warning restore 1591 #endif /// /// Hides the enumerable sequence object identity. /// /// Source sequence element type. /// Source sequence. /// Enumerable sequence with the same behavior as the original, but hiding the source object identity. /// AsQueryable doesn't hide the object identity, and simply acts as a cast to the IQueryable<TSource> interface. public static IQueryable Hide(this IQueryable source) { if (source == null) throw new ArgumentNullException("source"); return source.Provider.CreateQuery( Expression.Call( null, ((MethodInfo)MethodInfo.GetCurrentMethod()).MakeGenericMethod(typeof(TSource)), source.Expression ) ); } #pragma warning disable 1591 [EditorBrowsable(EditorBrowsableState.Never)] public static IEnumerable Hide(IEnumerable source) { return EnumerableEx.Hide(source); } #pragma warning restore 1591 /// /// Lazily invokes an action for each value in the sequence. /// /// Source sequence element type. /// Source sequence. /// Action to invoke for each element. /// Sequence exhibiting the specified side-effects upon enumeration. public static IQueryable Do(this IQueryable source, Expression> onNext) { if (source == null) throw new ArgumentNullException("source"); if (onNext == null) throw new ArgumentNullException("onNext"); return source.Provider.CreateQuery( Expression.Call( null, ((MethodInfo)MethodInfo.GetCurrentMethod()).MakeGenericMethod(typeof(TSource)), source.Expression, onNext ) ); } #pragma warning disable 1591 [EditorBrowsable(EditorBrowsableState.Never)] public static IEnumerable Do(IEnumerable source, Action onNext) { return EnumerableEx.Do(source, onNext); } #pragma warning restore 1591 /// /// Lazily invokes an action for each value in the sequence, and executes an action for successful termination. /// /// Source sequence element type. /// Source sequence. /// Action to invoke for each element. /// Action to invoke on successful termination of the sequence. /// Sequence exhibiting the specified side-effects upon enumeration. public static IQueryable Do(this IQueryable source, Expression> onNext, Expression onCompleted) { if (source == null) throw new ArgumentNullException("source"); if (onNext == null) throw new ArgumentNullException("onNext"); if (onCompleted == null) throw new ArgumentNullException("onCompleted"); return source.Provider.CreateQuery( Expression.Call( null, ((MethodInfo)MethodInfo.GetCurrentMethod()).MakeGenericMethod(typeof(TSource)), source.Expression, onNext, onCompleted ) ); } #pragma warning disable 1591 [EditorBrowsable(EditorBrowsableState.Never)] public static IEnumerable Do(IEnumerable source, Action onNext, Action onCompleted) { return EnumerableEx.Do(source, onNext, onCompleted); } #pragma warning restore 1591 /// /// Lazily invokes an action for each value in the sequence, and executes an action upon exceptional termination. /// /// Source sequence element type. /// Source sequence. /// Action to invoke for each element. /// Action to invoke on exceptional termination of the sequence. /// Sequence exhibiting the specified side-effects upon enumeration. public static IQueryable Do(this IQueryable source, Expression> onNext, Expression> onError) { if (source == null) throw new ArgumentNullException("source"); if (onNext == null) throw new ArgumentNullException("onNext"); if (onError == null) throw new ArgumentNullException("onError"); return source.Provider.CreateQuery( Expression.Call( null, ((MethodInfo)MethodInfo.GetCurrentMethod()).MakeGenericMethod(typeof(TSource)), source.Expression, onNext, onError ) ); } #pragma warning disable 1591 [EditorBrowsable(EditorBrowsableState.Never)] public static IEnumerable Do(IEnumerable source, Action onNext, Action onError) { return EnumerableEx.Do(source, onNext, onError); } #pragma warning restore 1591 /// /// Lazily invokes an action for each value in the sequence, and executes an action upon successful or exceptional termination. /// /// Source sequence element type. /// Source sequence. /// Action to invoke for each element. /// Action to invoke on exceptional termination of the sequence. /// Action to invoke on successful termination of the sequence. /// Sequence exhibiting the specified side-effects upon enumeration. public static IQueryable Do(this IQueryable source, Expression> onNext, Expression> onError, Expression onCompleted) { if (source == null) throw new ArgumentNullException("source"); if (onNext == null) throw new ArgumentNullException("onNext"); if (onError == null) throw new ArgumentNullException("onError"); if (onCompleted == null) throw new ArgumentNullException("onCompleted"); return source.Provider.CreateQuery( Expression.Call( null, ((MethodInfo)MethodInfo.GetCurrentMethod()).MakeGenericMethod(typeof(TSource)), source.Expression, onNext, onError, onCompleted ) ); } #pragma warning disable 1591 [EditorBrowsable(EditorBrowsableState.Never)] public static IEnumerable Do(IEnumerable source, Action onNext, Action onError, Action onCompleted) { return EnumerableEx.Do(source, onNext, onError, onCompleted); } #pragma warning restore 1591 #if !NO_RXINTERFACES /// /// Lazily invokes observer methods for each value in the sequence, and upon successful or exceptional termination. /// /// Source sequence element type. /// Source sequence. /// Observer to invoke notification calls on. /// Sequence exhibiting the side-effects of observer method invocation upon enumeration. public static IQueryable Do(this IQueryable source, IObserver observer) { if (source == null) throw new ArgumentNullException("source"); if (observer == null) throw new ArgumentNullException("observer"); return source.Provider.CreateQuery( Expression.Call( null, ((MethodInfo)MethodInfo.GetCurrentMethod()).MakeGenericMethod(typeof(TSource)), source.Expression, Expression.Constant(observer, typeof(IObserver)) ) ); } #pragma warning disable 1591 [EditorBrowsable(EditorBrowsableState.Never)] public static IEnumerable Do(IEnumerable source, IObserver observer) { return EnumerableEx.Do(source, observer); } #pragma warning restore 1591 #endif /// /// Generates a sequence of non-overlapping adjacent buffers over the source sequence. /// /// Source sequence element type. /// Source sequence. /// Number of elements for allocated buffers. /// Sequence of buffers containing source sequence elements. public static IQueryable> Buffer(this IQueryable source, int count) { if (source == null) throw new ArgumentNullException("source"); return source.Provider.CreateQuery>( Expression.Call( null, ((MethodInfo)MethodInfo.GetCurrentMethod()).MakeGenericMethod(typeof(TSource)), source.Expression, Expression.Constant(count, typeof(int)) ) ); } #pragma warning disable 1591 [EditorBrowsable(EditorBrowsableState.Never)] public static IEnumerable> Buffer(IEnumerable source, int count) { return EnumerableEx.Buffer(source, count); } #pragma warning restore 1591 /// /// Generates a sequence of buffers over the source sequence, with specified length and possible overlap. /// /// Source sequence element type. /// Source sequence. /// Number of elements for allocated buffers. /// Number of elements to skip between the start of consecutive buffers. /// Sequence of buffers containing source sequence elements. public static IQueryable> Buffer(this IQueryable source, int count, int skip) { if (source == null) throw new ArgumentNullException("source"); return source.Provider.CreateQuery>( Expression.Call( null, ((MethodInfo)MethodInfo.GetCurrentMethod()).MakeGenericMethod(typeof(TSource)), source.Expression, Expression.Constant(count, typeof(int)), Expression.Constant(skip, typeof(int)) ) ); } #pragma warning disable 1591 [EditorBrowsable(EditorBrowsableState.Never)] public static IEnumerable> Buffer(IEnumerable source, int count, int skip) { return EnumerableEx.Buffer(source, count, skip); } #pragma warning restore 1591 /// /// Ignores all elements in the source sequence. /// /// Source sequence element type. /// Source sequence. /// Source sequence without its elements. public static IQueryable IgnoreElements(this IQueryable source) { if (source == null) throw new ArgumentNullException("source"); return source.Provider.CreateQuery( Expression.Call( null, ((MethodInfo)MethodInfo.GetCurrentMethod()).MakeGenericMethod(typeof(TSource)), source.Expression ) ); } #pragma warning disable 1591 [EditorBrowsable(EditorBrowsableState.Never)] public static IEnumerable IgnoreElements(IEnumerable source) { return EnumerableEx.IgnoreElements(source); } #pragma warning restore 1591 /// /// Returns elements with a distinct key value by using the default equality comparer to compare key values. /// /// Source sequence element type. /// Key type. /// Source sequence. /// Key selector. /// Sequence that contains the elements from the source sequence with distinct key values. public static IQueryable Distinct(this IQueryable source, Expression> keySelector) { if (source == null) throw new ArgumentNullException("source"); if (keySelector == null) throw new ArgumentNullException("keySelector"); return source.Provider.CreateQuery( Expression.Call( null, ((MethodInfo)MethodInfo.GetCurrentMethod()).MakeGenericMethod(typeof(TSource), typeof(TKey)), source.Expression, keySelector ) ); } #pragma warning disable 1591 [EditorBrowsable(EditorBrowsableState.Never)] public static IEnumerable Distinct(IEnumerable source, Func keySelector) { return EnumerableEx.Distinct(source, keySelector); } #pragma warning restore 1591 /// /// Returns elements with a distinct key value by using the specified equality comparer to compare key values. /// /// Source sequence element type. /// Key type. /// Source sequence. /// Key selector. /// Comparer used to compare key values. /// Sequence that contains the elements from the source sequence with distinct key values. public static IQueryable Distinct(this IQueryable source, Expression> keySelector, IEqualityComparer comparer) { if (source == null) throw new ArgumentNullException("source"); if (keySelector == null) throw new ArgumentNullException("keySelector"); if (comparer == null) throw new ArgumentNullException("comparer"); return source.Provider.CreateQuery( Expression.Call( null, ((MethodInfo)MethodInfo.GetCurrentMethod()).MakeGenericMethod(typeof(TSource), typeof(TKey)), source.Expression, keySelector, Expression.Constant(comparer, typeof(IEqualityComparer)) ) ); } #pragma warning disable 1591 [EditorBrowsable(EditorBrowsableState.Never)] public static IEnumerable Distinct(IEnumerable source, Func keySelector, IEqualityComparer comparer) { return EnumerableEx.Distinct(source, keySelector, comparer); } #pragma warning restore 1591 /// /// Returns consecutive distinct elements by using the default equality comparer to compare values. /// /// Source sequence element type. /// Source sequence. /// Sequence without adjacent non-distinct elements. public static IQueryable DistinctUntilChanged(this IQueryable source) { if (source == null) throw new ArgumentNullException("source"); return source.Provider.CreateQuery( Expression.Call( null, ((MethodInfo)MethodInfo.GetCurrentMethod()).MakeGenericMethod(typeof(TSource)), source.Expression ) ); } #pragma warning disable 1591 [EditorBrowsable(EditorBrowsableState.Never)] public static IEnumerable DistinctUntilChanged(IEnumerable source) { return EnumerableEx.DistinctUntilChanged(source); } #pragma warning restore 1591 /// /// Returns consecutive distinct elements by using the specified equality comparer to compare values. /// /// Source sequence element type. /// Source sequence. /// Comparer used to compare values. /// Sequence without adjacent non-distinct elements. public static IQueryable DistinctUntilChanged(this IQueryable source, IEqualityComparer comparer) { if (source == null) throw new ArgumentNullException("source"); if (comparer == null) throw new ArgumentNullException("comparer"); return source.Provider.CreateQuery( Expression.Call( null, ((MethodInfo)MethodInfo.GetCurrentMethod()).MakeGenericMethod(typeof(TSource)), source.Expression, Expression.Constant(comparer, typeof(IEqualityComparer)) ) ); } #pragma warning disable 1591 [EditorBrowsable(EditorBrowsableState.Never)] public static IEnumerable DistinctUntilChanged(IEnumerable source, IEqualityComparer comparer) { return EnumerableEx.DistinctUntilChanged(source, comparer); } #pragma warning restore 1591 /// /// Returns consecutive distinct elements based on a key value by using the specified equality comparer to compare key values. /// /// Source sequence element type. /// Key type. /// Source sequence. /// Key selector. /// Sequence without adjacent non-distinct elements. public static IQueryable DistinctUntilChanged(this IQueryable source, Expression> keySelector) { if (source == null) throw new ArgumentNullException("source"); if (keySelector == null) throw new ArgumentNullException("keySelector"); return source.Provider.CreateQuery( Expression.Call( null, ((MethodInfo)MethodInfo.GetCurrentMethod()).MakeGenericMethod(typeof(TSource), typeof(TKey)), source.Expression, keySelector ) ); } #pragma warning disable 1591 [EditorBrowsable(EditorBrowsableState.Never)] public static IEnumerable DistinctUntilChanged(IEnumerable source, Func keySelector) { return EnumerableEx.DistinctUntilChanged(source, keySelector); } #pragma warning restore 1591 /// /// Returns consecutive distinct elements based on a key value by using the specified equality comparer to compare key values. /// /// Source sequence element type. /// Key type. /// Source sequence. /// Key selector. /// Comparer used to compare key values. /// Sequence without adjacent non-distinct elements. public static IQueryable DistinctUntilChanged(this IQueryable source, Expression> keySelector, IEqualityComparer comparer) { if (source == null) throw new ArgumentNullException("source"); if (keySelector == null) throw new ArgumentNullException("keySelector"); if (comparer == null) throw new ArgumentNullException("comparer"); return source.Provider.CreateQuery( Expression.Call( null, ((MethodInfo)MethodInfo.GetCurrentMethod()).MakeGenericMethod(typeof(TSource), typeof(TKey)), source.Expression, keySelector, Expression.Constant(comparer, typeof(IEqualityComparer)) ) ); } #pragma warning disable 1591 [EditorBrowsable(EditorBrowsableState.Never)] public static IEnumerable DistinctUntilChanged(IEnumerable source, Func keySelector, IEqualityComparer comparer) { return EnumerableEx.DistinctUntilChanged(source, keySelector, comparer); } #pragma warning restore 1591 /// /// Expands the sequence by recursively applying a selector function. /// /// Source sequence element type. /// Source sequence. /// Selector function to retrieve the next sequence to expand. /// Sequence with results from the recursive expansion of the source sequence. public static IQueryable Expand(this IQueryable source, Expression>> selector) { if (source == null) throw new ArgumentNullException("source"); if (selector == null) throw new ArgumentNullException("selector"); return source.Provider.CreateQuery( Expression.Call( null, ((MethodInfo)MethodInfo.GetCurrentMethod()).MakeGenericMethod(typeof(TSource)), source.Expression, selector ) ); } #pragma warning disable 1591 [EditorBrowsable(EditorBrowsableState.Never)] public static IEnumerable Expand(IEnumerable source, Func> selector) { return EnumerableEx.Expand(source, selector); } #pragma warning restore 1591 /// /// Returns the source sequence prefixed with the specified value. /// /// Source sequence element type. /// Source sequence. /// Values to prefix the sequence with. /// Sequence starting with the specified prefix value, followed by the source sequence. public static IQueryable StartWith(this IQueryable source, params TSource[] values) { if (source == null) throw new ArgumentNullException("source"); return source.Provider.CreateQuery( Expression.Call( null, ((MethodInfo)MethodInfo.GetCurrentMethod()).MakeGenericMethod(typeof(TSource)), source.Expression, Expression.Constant(values, typeof(TSource[])) ) ); } #pragma warning disable 1591 [EditorBrowsable(EditorBrowsableState.Never)] public static IEnumerable StartWith(IEnumerable source, params TSource[] values) { return EnumerableEx.StartWith(source, values); } #pragma warning restore 1591 /// /// Generates a sequence of accumulated values by scanning the source sequence and applying an accumulator function. /// /// Source sequence element type. /// Accumulation type. /// Source sequence. /// Accumulator seed value. /// Accumulation function to apply to the current accumulation value and each element of the sequence. /// Sequence with all intermediate accumulation values resulting from scanning the sequence. public static IQueryable Scan(this IQueryable source, TAccumulate seed, Expression> accumulator) { if (source == null) throw new ArgumentNullException("source"); if (accumulator == null) throw new ArgumentNullException("accumulator"); return source.Provider.CreateQuery( Expression.Call( null, ((MethodInfo)MethodInfo.GetCurrentMethod()).MakeGenericMethod(typeof(TSource), typeof(TAccumulate)), source.Expression, Expression.Constant(seed, typeof(TAccumulate)), accumulator ) ); } #pragma warning disable 1591 [EditorBrowsable(EditorBrowsableState.Never)] public static IEnumerable Scan(IEnumerable source, TAccumulate seed, Func accumulator) { return EnumerableEx.Scan(source, seed, accumulator); } #pragma warning restore 1591 /// /// Generates a sequence of accumulated values by scanning the source sequence and applying an accumulator function. /// /// Source sequence element type. /// Source sequence. /// Accumulation function to apply to the current accumulation value and each element of the sequence. /// Sequence with all intermediate accumulation values resulting from scanning the sequence. public static IQueryable Scan(this IQueryable source, Expression> accumulator) { if (source == null) throw new ArgumentNullException("source"); if (accumulator == null) throw new ArgumentNullException("accumulator"); return source.Provider.CreateQuery( Expression.Call( null, ((MethodInfo)MethodInfo.GetCurrentMethod()).MakeGenericMethod(typeof(TSource)), source.Expression, accumulator ) ); } #pragma warning disable 1591 [EditorBrowsable(EditorBrowsableState.Never)] public static IEnumerable Scan(IEnumerable source, Func accumulator) { return EnumerableEx.Scan(source, accumulator); } #pragma warning restore 1591 /// /// Returns a specified number of contiguous elements from the end of the sequence. /// /// Source sequence element type. /// Source sequence. /// The number of elements to take from the end of the sequence. /// Sequence with the specified number of elements counting from the end of the source sequence. public static IQueryable TakeLast(this IQueryable source, int count) { if (source == null) throw new ArgumentNullException("source"); return source.Provider.CreateQuery( Expression.Call( null, ((MethodInfo)MethodInfo.GetCurrentMethod()).MakeGenericMethod(typeof(TSource)), source.Expression, Expression.Constant(count, typeof(int)) ) ); } #pragma warning disable 1591 [EditorBrowsable(EditorBrowsableState.Never)] public static IEnumerable TakeLast(IEnumerable source, int count) { return EnumerableEx.TakeLast(source, count); } #pragma warning restore 1591 /// /// Bypasses a specified number of contiguous elements from the end of the sequence and returns the remaining elements. /// /// Source sequence element type. /// Source sequence. /// The number of elements to skip from the end of the sequence before returning the remaining elements. /// Sequence bypassing the specified number of elements counting from the end of the source sequence. public static IQueryable SkipLast(this IQueryable source, int count) { if (source == null) throw new ArgumentNullException("source"); return source.Provider.CreateQuery( Expression.Call( null, ((MethodInfo)MethodInfo.GetCurrentMethod()).MakeGenericMethod(typeof(TSource)), source.Expression, Expression.Constant(count, typeof(int)) ) ); } #pragma warning disable 1591 [EditorBrowsable(EditorBrowsableState.Never)] public static IEnumerable SkipLast(IEnumerable source, int count) { return EnumerableEx.SkipLast(source, count); } #pragma warning restore 1591 /// /// Repeats and concatenates the source sequence infinitely. /// /// Source sequence element type. /// Source sequence. /// Sequence obtained by concatenating the source sequence to itself infinitely. public static IQueryable Repeat(this IQueryable source) { if (source == null) throw new ArgumentNullException("source"); return source.Provider.CreateQuery( Expression.Call( null, ((MethodInfo)MethodInfo.GetCurrentMethod()).MakeGenericMethod(typeof(TSource)), source.Expression ) ); } #pragma warning disable 1591 [EditorBrowsable(EditorBrowsableState.Never)] public static IEnumerable Repeat(IEnumerable source) { return EnumerableEx.Repeat(source); } #pragma warning restore 1591 /// /// Repeats and concatenates the source sequence the given number of times. /// /// Source sequence element type. /// Source sequence. /// Number of times to repeat the source sequence. /// Sequence obtained by concatenating the source sequence to itself the specified number of times. public static IQueryable Repeat(this IQueryable source, int count) { if (source == null) throw new ArgumentNullException("source"); return source.Provider.CreateQuery( Expression.Call( null, ((MethodInfo)MethodInfo.GetCurrentMethod()).MakeGenericMethod(typeof(TSource)), source.Expression, Expression.Constant(count, typeof(int)) ) ); } #pragma warning disable 1591 [EditorBrowsable(EditorBrowsableState.Never)] public static IEnumerable Repeat(IEnumerable source, int count) { return EnumerableEx.Repeat(source, count); } #pragma warning restore 1591 /// /// Returns a sequence with no elements. /// /// Result sequence element type. /// Query provider. /// Sequence with no elements. public static IQueryable Empty(this IQueryProvider provider) { if (provider == null) throw new ArgumentNullException("provider"); return provider.CreateQuery( Expression.Call( null, ((MethodInfo)MethodInfo.GetCurrentMethod()).MakeGenericMethod(typeof(TResult)), Expression.Constant(provider, typeof(IQueryProvider)) ) ); } #pragma warning disable 1591 [EditorBrowsable(EditorBrowsableState.Never)] public static /*!*/IQueryable Empty() { return Enumerable.Empty().AsQueryable(); } #pragma warning restore 1591 /// /// Generates a sequence of integral numbers within a specified range. /// /// Query provider. /// The value of the first integer in the sequence. /// The number of sequential integers to generate. /// Sequence that contains a range of sequential integral numbers. public static IQueryable Range(this IQueryProvider provider, int start, int count) { if (provider == null) throw new ArgumentNullException("provider"); return provider.CreateQuery( Expression.Call( null, (MethodInfo)MethodInfo.GetCurrentMethod(), Expression.Constant(provider, typeof(IQueryProvider)), Expression.Constant(start, typeof(int)), Expression.Constant(count, typeof(int)) ) ); } #pragma warning disable 1591 [EditorBrowsable(EditorBrowsableState.Never)] public static /*!*/IQueryable Range(int start, int count) { return Enumerable.Range(start, count).AsQueryable(); } #pragma warning restore 1591 /// /// Generates a sequence that contains one repeated value. /// /// Result sequence element type. /// Query provider. /// The value to be repeated. /// The number of times to repeat the value in the generated sequence. /// Sequence that contains a repeated value. public static IQueryable Repeat(this IQueryProvider provider, TResult element, int count) { if (provider == null) throw new ArgumentNullException("provider"); return provider.CreateQuery( Expression.Call( null, ((MethodInfo)MethodInfo.GetCurrentMethod()).MakeGenericMethod(typeof(TResult)), Expression.Constant(provider, typeof(IQueryProvider)), Expression.Constant(element, typeof(TResult)), Expression.Constant(count, typeof(int)) ) ); } #pragma warning disable 1591 [EditorBrowsable(EditorBrowsableState.Never)] public static /*!*/IQueryable Repeat(TResult element, int count) { return EnumerableEx.Repeat(element, count).AsQueryable(); } #pragma warning restore 1591 /// /// Gets the local Queryable provider. /// public static IQueryProvider Provider { get { return new QueryProviderShim(); } } class QueryProviderShim : IQueryProvider { public IQueryable CreateQuery(Expression expression) { var provider = new TElement[0].AsQueryable().Provider; var res = Redir(expression); return provider.CreateQuery(res); } public IQueryable CreateQuery(Expression expression) { return CreateQuery(expression); } public TResult Execute(Expression expression) { var provider = new TResult[0].AsQueryable().Provider; var res = Redir(expression); return provider.Execute(res); } public object Execute(Expression expression) { return Execute(expression); } private static Expression Redir(Expression expression) { var mce = expression as MethodCallExpression; if (mce != null && mce.Method.DeclaringType == typeof(QueryableEx)) { if (mce.Arguments.Count >= 1 && typeof(IQueryProvider).IsAssignableFrom(mce.Arguments[0].Type)) { var ce = mce.Arguments[0] as ConstantExpression; if (ce != null) { if (ce.Value is QueryProviderShim) { var targetType = typeof(QueryableEx); var method = mce.Method; var methods = GetMethods(targetType); var arguments = mce.Arguments.Skip(1).ToList(); // // From all the operators with the method's name, find the one that matches all arguments. // var typeArgs = method.IsGenericMethod ? method.GetGenericArguments() : null; var targetMethod = methods[method.Name].FirstOrDefault(candidateMethod => ArgsMatch(candidateMethod, arguments, typeArgs)); if (targetMethod == null) throw new InvalidOperationException(string.Format(CultureInfo.CurrentCulture, "There is no method '{0}' on type '{1}' that matches the specified arguments", method.Name, targetType.Name)); // // Restore generic arguments. // if (typeArgs != null) targetMethod = targetMethod.MakeGenericMethod(typeArgs); // // Finally, we need to deal with mismatches on Expression> versus Func<...>. // var parameters = targetMethod.GetParameters(); for (int i = 0, n = parameters.Length; i < n; i++) { arguments[i] = Unquote(arguments[i]); } // // Emit a new call to the discovered target method. // return Expression.Call(null, targetMethod, arguments); } } } } return expression; } private static ILookup GetMethods(Type type) { return type.GetMethods(BindingFlags.Static | BindingFlags.Public).ToLookup(m => m.Name); } private static bool ArgsMatch(MethodInfo method, IList arguments, Type[] typeArgs) { // // Number of parameters should match. Notice we've sanitized IQueryProvider "this" // parameters first (see Redir). // var parameters = method.GetParameters(); if (parameters.Length != arguments.Count) return false; // // Genericity should match too. // if (!method.IsGenericMethod && typeArgs != null && typeArgs.Length > 0) return false; // // Reconstruct the generic method if needed. // if (method.IsGenericMethodDefinition) { if (typeArgs == null) return false; if (method.GetGenericArguments().Length != typeArgs.Length) return false; var result = method.MakeGenericMethod(typeArgs); parameters = result.GetParameters(); } // // Check compatibility for the parameter types. // for (int i = 0, n = arguments.Count; i < n; i++) { var parameterType = parameters[i].ParameterType; var argument = arguments[i]; // // For operators that take a function (like Where, Select), we'll be faced // with a quoted argument and a discrepancy between Expression> // and the underlying Func<...>. // if (!parameterType.IsAssignableFrom(argument.Type)) { argument = Unquote(argument); if (!parameterType.IsAssignableFrom(argument.Type)) return false; } } return true; } private static Expression Unquote(Expression expression) { // // Get rid of all outer quotes around an expression. // while (expression.NodeType == ExpressionType.Quote) expression = ((UnaryExpression)expression).Operand; return expression; } } internal static Expression GetSourceExpression(IEnumerable source) { var q = source as IQueryable; if (q != null) return q.Expression; return Expression.Constant(source, typeof(IEnumerable)); } internal static Expression GetSourceExpression(IEnumerable[] sources) { return Expression.NewArrayInit( typeof(IEnumerable), sources.Select(source => GetSourceExpression(source)) ); } } }