// Licensed to the .NET Foundation under one or more agreements.
// The .NET Foundation licenses this file to you under the Apache 2.0 License.
// See the LICENSE file in the project root for more 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(nameof(source));
            return source.Provider.Execute(
                Expression.Call(
                    null,
#if CRIPPLED_REFLECTION
                    InfoOf(() => QueryableEx.IsEmpty(default(IQueryable))),
#else
                    ((MethodInfo)MethodInfo.GetCurrentMethod()).MakeGenericMethod(typeof(TSource)),
#endif
                    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(nameof(source));
            if (comparer == null)
                throw new ArgumentNullException(nameof(comparer));
            return source.Provider.Execute(
                Expression.Call(
                    null,
#if CRIPPLED_REFLECTION
                    InfoOf(() => QueryableEx.Min(default(IQueryable), default(IComparer))),
#else
                    ((MethodInfo)MethodInfo.GetCurrentMethod()).MakeGenericMethod(typeof(TSource)),
#endif
                    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(nameof(source));
            if (keySelector == null)
                throw new ArgumentNullException(nameof(keySelector));
            return source.Provider.Execute>(
                Expression.Call(
                    null,
#if CRIPPLED_REFLECTION
                    InfoOf(() => QueryableEx.MinBy(default(IQueryable), default(Expression>))),
#else
                    ((MethodInfo)MethodInfo.GetCurrentMethod()).MakeGenericMethod(typeof(TSource), typeof(TKey)),
#endif
                    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(nameof(source));
            if (keySelector == null)
                throw new ArgumentNullException(nameof(keySelector));
            if (comparer == null)
                throw new ArgumentNullException(nameof(comparer));
            return source.Provider.Execute>(
                Expression.Call(
                    null,
#if CRIPPLED_REFLECTION
                    InfoOf(() => QueryableEx.MinBy(default(IQueryable), default(Expression>), default(IComparer))),
#else
                    ((MethodInfo)MethodInfo.GetCurrentMethod()).MakeGenericMethod(typeof(TSource), typeof(TKey)),
#endif
                    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(nameof(source));
            if (comparer == null)
                throw new ArgumentNullException(nameof(comparer));
            return source.Provider.Execute(
                Expression.Call(
                    null,
#if CRIPPLED_REFLECTION
                    InfoOf(() => QueryableEx.Max(default(IQueryable), default(IComparer))),
#else
                    ((MethodInfo)MethodInfo.GetCurrentMethod()).MakeGenericMethod(typeof(TSource)),
#endif
                    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(nameof(source));
            if (keySelector == null)
                throw new ArgumentNullException(nameof(keySelector));
            return source.Provider.Execute>(
                Expression.Call(
                    null,
#if CRIPPLED_REFLECTION
                    InfoOf(() => QueryableEx.MaxBy(default(IQueryable), default(Expression>))),
#else
                    ((MethodInfo)MethodInfo.GetCurrentMethod()).MakeGenericMethod(typeof(TSource), typeof(TKey)),
#endif
                    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(nameof(source));
            if (keySelector == null)
                throw new ArgumentNullException(nameof(keySelector));
            if (comparer == null)
                throw new ArgumentNullException(nameof(comparer));
            return source.Provider.Execute>(
                Expression.Call(
                    null,
#if CRIPPLED_REFLECTION
                    InfoOf(() => QueryableEx.MaxBy(default(IQueryable), default(Expression>), default(IComparer))),
#else
                    ((MethodInfo)MethodInfo.GetCurrentMethod()).MakeGenericMethod(typeof(TSource), typeof(TKey)),
#endif
                    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(nameof(source));
            if (selector == null)
                throw new ArgumentNullException(nameof(selector));
            return source.Provider.CreateQuery(
                Expression.Call(
                    null,
#if CRIPPLED_REFLECTION
                    InfoOf(() => QueryableEx.Share(default(IQueryable), default(Expression, IEnumerable>>))),
#else
                    ((MethodInfo)MethodInfo.GetCurrentMethod()).MakeGenericMethod(typeof(TSource), typeof(TResult)),
#endif
                    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(nameof(source));
            if (selector == null)
                throw new ArgumentNullException(nameof(selector));
            return source.Provider.CreateQuery(
                Expression.Call(
                    null,
#if CRIPPLED_REFLECTION
                    InfoOf(() => QueryableEx.Publish(default(IQueryable), default(Expression, IEnumerable>>))),
#else
                    ((MethodInfo)MethodInfo.GetCurrentMethod()).MakeGenericMethod(typeof(TSource), typeof(TResult)),
#endif
                    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(nameof(source));
            if (selector == null)
                throw new ArgumentNullException(nameof(selector));
            return source.Provider.CreateQuery(
                Expression.Call(
                    null,
#if CRIPPLED_REFLECTION
                    InfoOf(() => QueryableEx.Memoize(default(IQueryable), default(Expression, IEnumerable>>))),
#else
                    ((MethodInfo)MethodInfo.GetCurrentMethod()).MakeGenericMethod(typeof(TSource), typeof(TResult)),
#endif
                    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(nameof(source));
            if (selector == null)
                throw new ArgumentNullException(nameof(selector));
            return source.Provider.CreateQuery(
                Expression.Call(
                    null,
#if CRIPPLED_REFLECTION
                    InfoOf(() => QueryableEx.Memoize(default(IQueryable), default(int), default(Expression, IEnumerable>>))),
#else
                    ((MethodInfo)MethodInfo.GetCurrentMethod()).MakeGenericMethod(typeof(TSource), typeof(TResult)),
#endif
                    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(nameof(provider));
            if (getEnumerator == null)
                throw new ArgumentNullException(nameof(getEnumerator));
            return provider.CreateQuery(
                Expression.Call(
                    null,
#if CRIPPLED_REFLECTION
                    InfoOf(() => QueryableEx.Create(default(IQueryProvider), default(Expression>>))),
#else
                    ((MethodInfo)MethodInfo.GetCurrentMethod()).MakeGenericMethod(typeof(TResult)),
#endif
                    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(nameof(provider));
            return provider.CreateQuery(
                Expression.Call(
                    null,
#if CRIPPLED_REFLECTION
                    InfoOf(() => QueryableEx.Return(default(IQueryProvider), default(TResult))),
#else
                    ((MethodInfo)MethodInfo.GetCurrentMethod()).MakeGenericMethod(typeof(TResult)),
#endif
                    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(nameof(provider));
            if (exception == null)
                throw new ArgumentNullException(nameof(exception));
            return provider.CreateQuery(
                Expression.Call(
                    null,
#if CRIPPLED_REFLECTION
                    InfoOf(() => QueryableEx.Throw(default(IQueryProvider), default(Exception))),
#else
                    ((MethodInfo)MethodInfo.GetCurrentMethod()).MakeGenericMethod(typeof(TResult)),
#endif
                    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(nameof(provider));
            if (enumerableFactory == null)
                throw new ArgumentNullException(nameof(enumerableFactory));
            return provider.CreateQuery(
                Expression.Call(
                    null,
#if CRIPPLED_REFLECTION
                    InfoOf(() => QueryableEx.Defer(default(IQueryProvider), default(Expression>>))),
#else
                    ((MethodInfo)MethodInfo.GetCurrentMethod()).MakeGenericMethod(typeof(TResult)),
#endif
                    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(nameof(provider));
            if (condition == null)
                throw new ArgumentNullException(nameof(condition));
            if (iterate == null)
                throw new ArgumentNullException(nameof(iterate));
            if (resultSelector == null)
                throw new ArgumentNullException(nameof(resultSelector));
            return provider.CreateQuery(
                Expression.Call(
                    null,
#if CRIPPLED_REFLECTION
                    InfoOf(() => QueryableEx.Generate(default(IQueryProvider), default(TState), default(Expression>), default(Expression>), default(Expression>))),
#else
                    ((MethodInfo)MethodInfo.GetCurrentMethod()).MakeGenericMethod(typeof(TState), typeof(TResult)),
#endif
                    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(nameof(provider));
            if (resourceFactory == null)
                throw new ArgumentNullException(nameof(resourceFactory));
            if (enumerableFactory == null)
                throw new ArgumentNullException(nameof(enumerableFactory));
            return provider.CreateQuery(
                Expression.Call(
                    null,
#if CRIPPLED_REFLECTION
                    InfoOf(() => QueryableEx.Using(default(IQueryProvider), default(Expression>), default(Expression>>))),
#else
                    ((MethodInfo)MethodInfo.GetCurrentMethod()).MakeGenericMethod(typeof(TSource), typeof(TResource)),
#endif
                    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(nameof(provider));
            return provider.CreateQuery(
                Expression.Call(
                    null,
#if CRIPPLED_REFLECTION
                    InfoOf(() => QueryableEx.Repeat(default(IQueryProvider), default(TResult))),
#else
                    ((MethodInfo)MethodInfo.GetCurrentMethod()).MakeGenericMethod(typeof(TResult)),
#endif
                    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(nameof(source));
            if (handler == null)
                throw new ArgumentNullException(nameof(handler));
            return source.Provider.CreateQuery(
                Expression.Call(
                    null,
#if CRIPPLED_REFLECTION
                    InfoOf(() => QueryableEx.Catch(default(IQueryable), default(Expression>>))),
#else
                    ((MethodInfo)MethodInfo.GetCurrentMethod()).MakeGenericMethod(typeof(TSource), typeof(TException)),
#endif
                    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(nameof(sources));
            return sources.Provider.CreateQuery(
                Expression.Call(
                    null,
#if CRIPPLED_REFLECTION
                    InfoOf(() => QueryableEx.Catch(default(IQueryable>))),
#else
                    ((MethodInfo)MethodInfo.GetCurrentMethod()).MakeGenericMethod(typeof(TSource)),
#endif
                    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(nameof(provider));
            if (sources == null)
                throw new ArgumentNullException(nameof(sources));
            return provider.CreateQuery(
                Expression.Call(
                    null,
#if CRIPPLED_REFLECTION
                    InfoOf(() => QueryableEx.Catch(default(IQueryProvider), default(IEnumerable[]))),
#else
                    ((MethodInfo)MethodInfo.GetCurrentMethod()).MakeGenericMethod(typeof(TSource)),
#endif
                    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(nameof(first));
            if (second == null)
                throw new ArgumentNullException(nameof(second));
            return first.Provider.CreateQuery(
                Expression.Call(
                    null,
#if CRIPPLED_REFLECTION
                    InfoOf(() => QueryableEx.Catch(default(IQueryable), default(IEnumerable))),
#else
                    ((MethodInfo)MethodInfo.GetCurrentMethod()).MakeGenericMethod(typeof(TSource)),
#endif
                    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