From 1a550b39d0dbf64f7ffb8f59951e748dc0382b62 Mon Sep 17 00:00:00 2001 From: dotnet-bot Date: Fri, 13 Mar 2015 14:45:08 -0700 Subject: [PATCH] Add System.Linq.Queryable Source and Tests --- .../System.Linq.Queryable.sln | 28 + src/System.Linq.Queryable/src/Resources/SR.cs | 51 + .../src/Resources/Strings.resx | 138 ++ .../src/System.Linq.Queryable.csproj | 35 + .../src/System/Linq/EnumerableExecutor.cs | 50 + .../src/System/Linq/EnumerableQuery.cs | 155 ++ .../src/System/Linq/EnumerableRewriter.cs | 247 +++ .../src/System/Linq/Error.cs | 48 + .../Linq/Expressions/OldExpressionVisitor.cs | 367 ++++ .../ReadOnlyCollectionExtensions.cs | 34 + .../src/System/Linq/Queryable.cs | 1743 +++++++++++++++++ .../src/System/Linq/Strings.cs | 41 + .../src/System/Linq/TypeHelper.cs | 57 + src/System.Linq.Queryable/src/packages.config | 15 + src/System.Linq.Queryable/tests/Queryable.cs | 875 +++++++++ .../tests/System.Linq.Queryable.Tests.csproj | 30 + .../tests/packages.config | 21 + 17 files changed, 3935 insertions(+) create mode 100644 src/System.Linq.Queryable/System.Linq.Queryable.sln create mode 100644 src/System.Linq.Queryable/src/Resources/SR.cs create mode 100644 src/System.Linq.Queryable/src/Resources/Strings.resx create mode 100644 src/System.Linq.Queryable/src/System.Linq.Queryable.csproj create mode 100644 src/System.Linq.Queryable/src/System/Linq/EnumerableExecutor.cs create mode 100644 src/System.Linq.Queryable/src/System/Linq/EnumerableQuery.cs create mode 100644 src/System.Linq.Queryable/src/System/Linq/EnumerableRewriter.cs create mode 100644 src/System.Linq.Queryable/src/System/Linq/Error.cs create mode 100644 src/System.Linq.Queryable/src/System/Linq/Expressions/OldExpressionVisitor.cs create mode 100644 src/System.Linq.Queryable/src/System/Linq/Expressions/ReadOnlyCollectionExtensions.cs create mode 100644 src/System.Linq.Queryable/src/System/Linq/Queryable.cs create mode 100644 src/System.Linq.Queryable/src/System/Linq/Strings.cs create mode 100644 src/System.Linq.Queryable/src/System/Linq/TypeHelper.cs create mode 100644 src/System.Linq.Queryable/src/packages.config create mode 100644 src/System.Linq.Queryable/tests/Queryable.cs create mode 100644 src/System.Linq.Queryable/tests/System.Linq.Queryable.Tests.csproj create mode 100644 src/System.Linq.Queryable/tests/packages.config diff --git a/src/System.Linq.Queryable/System.Linq.Queryable.sln b/src/System.Linq.Queryable/System.Linq.Queryable.sln new file mode 100644 index 000000000000..2891d7228ae1 --- /dev/null +++ b/src/System.Linq.Queryable/System.Linq.Queryable.sln @@ -0,0 +1,28 @@ + +Microsoft Visual Studio Solution File, Format Version 12.00 +# Visual Studio 2013 +VisualStudioVersion = 12.0.31101.0 +MinimumVisualStudioVersion = 10.0.40219.1 +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "System.Linq.Queryable", "src\System.Linq.Queryable.csproj", "{BE12B753-C130-4B68-86E3-877F1AEE52C0}" +EndProject +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "System.Linq.Queryable.Tests", "tests\System.Linq.Queryable.Tests.csproj", "{7B88D79B-B799-4116-A7D0-AED572540CD4}" +EndProject +Global + GlobalSection(SolutionConfigurationPlatforms) = preSolution + Debug|Any CPU = Debug|Any CPU + Release|Any CPU = Release|Any CPU + EndGlobalSection + GlobalSection(ProjectConfigurationPlatforms) = postSolution + {BE12B753-C130-4B68-86E3-877F1AEE52C0}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {BE12B753-C130-4B68-86E3-877F1AEE52C0}.Debug|Any CPU.Build.0 = Debug|Any CPU + {BE12B753-C130-4B68-86E3-877F1AEE52C0}.Release|Any CPU.ActiveCfg = Release|Any CPU + {BE12B753-C130-4B68-86E3-877F1AEE52C0}.Release|Any CPU.Build.0 = Release|Any CPU + {7B88D79B-B799-4116-A7D0-AED572540CD4}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {7B88D79B-B799-4116-A7D0-AED572540CD4}.Debug|Any CPU.Build.0 = Debug|Any CPU + {7B88D79B-B799-4116-A7D0-AED572540CD4}.Release|Any CPU.ActiveCfg = Release|Any CPU + {7B88D79B-B799-4116-A7D0-AED572540CD4}.Release|Any CPU.Build.0 = Release|Any CPU + EndGlobalSection + GlobalSection(SolutionProperties) = preSolution + HideSolutionNode = FALSE + EndGlobalSection +EndGlobal diff --git a/src/System.Linq.Queryable/src/Resources/SR.cs b/src/System.Linq.Queryable/src/Resources/SR.cs new file mode 100644 index 000000000000..a51979ed3911 --- /dev/null +++ b/src/System.Linq.Queryable/src/Resources/SR.cs @@ -0,0 +1,51 @@ +// Do not edit this file manually it is auto-generated during the build based on the .resx file for this project. +namespace System +{ + internal static partial class SR + { +#pragma warning disable 0414 + private const string s_resourcesName = "System.Linq.Queryable.resources"; // assembly Name + .resources +#pragma warning restore 0414 + +#if !DEBUGRESOURCES + internal static string ArgumentNotIEnumerableGeneric { + get { return SR.GetResourceString("ArgumentNotIEnumerableGeneric", null); } + } + internal static string UnhandledExpressionType { + get { return SR.GetResourceString("UnhandledExpressionType", null); } + } + internal static string UnhandledBindingType { + get { return SR.GetResourceString("UnhandledBindingType", null); } + } + internal static string ArgumentNotValid { + get { return SR.GetResourceString("ArgumentNotValid", null); } + } + internal static string NoMethodOnType { + get { return SR.GetResourceString("NoMethodOnType", null); } + } + internal static string NoMethodOnTypeMatchingArguments { + get { return SR.GetResourceString("NoMethodOnTypeMatchingArguments", null); } + } +#else + internal static string ArgumentNotIEnumerableGeneric { + get { return SR.GetResourceString("ArgumentNotIEnumerableGeneric", @"{0} is not IEnumerable<>"); } + } + internal static string UnhandledExpressionType { + get { return SR.GetResourceString("UnhandledExpressionType", @"Unhandled Expression Type: {0}"); } + } + internal static string UnhandledBindingType { + get { return SR.GetResourceString("UnhandledBindingType", @"Unhandled Binding Type: {0}"); } + } + internal static string ArgumentNotValid { + get { return SR.GetResourceString("ArgumentNotValid", @"Argument {0} is not valid"); } + } + internal static string NoMethodOnType { + get { return SR.GetResourceString("NoMethodOnType", @"There is no method '{0}' on type '{1}'"); } + } + internal static string NoMethodOnTypeMatchingArguments { + get { return SR.GetResourceString("NoMethodOnTypeMatchingArguments", @"There is no method '{0}' on type '{1}' that matches the specified arguments"); } + } + +#endif + } +} diff --git a/src/System.Linq.Queryable/src/Resources/Strings.resx b/src/System.Linq.Queryable/src/Resources/Strings.resx new file mode 100644 index 000000000000..1a9854307ffb --- /dev/null +++ b/src/System.Linq.Queryable/src/Resources/Strings.resx @@ -0,0 +1,138 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + text/microsoft-resx + + + 2.0 + + + System.Resources.ResXResourceReader, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + + System.Resources.ResXResourceWriter, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + + {0} is not IEnumerable<> + + + Unhandled Expression Type: {0} + + + Unhandled Binding Type: {0} + + + Argument {0} is not valid + + + There is no method '{0}' on type '{1}' + + + There is no method '{0}' on type '{1}' that matches the specified arguments + + \ No newline at end of file diff --git a/src/System.Linq.Queryable/src/System.Linq.Queryable.csproj b/src/System.Linq.Queryable/src/System.Linq.Queryable.csproj new file mode 100644 index 000000000000..a2d7d1ca9c1f --- /dev/null +++ b/src/System.Linq.Queryable/src/System.Linq.Queryable.csproj @@ -0,0 +1,35 @@ + + + + + Debug + AnyCPU + {BE12B753-C130-4B68-86E3-877F1AEE52C0} + Library + System.Linq.Queryable + System.Linq.Queryable + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/src/System.Linq.Queryable/src/System/Linq/EnumerableExecutor.cs b/src/System.Linq.Queryable/src/System/Linq/EnumerableExecutor.cs new file mode 100644 index 000000000000..bcc84911b7be --- /dev/null +++ b/src/System.Linq.Queryable/src/System/Linq/EnumerableExecutor.cs @@ -0,0 +1,50 @@ +// Copyright (c) Microsoft. All rights reserved. +// Licensed under the MIT license. See LICENSE file in the project root for full license information. + +using System.Collections.Generic; +using System.Linq.Expressions; + +namespace System.Linq +{ + // Must remain public for Silverlight + public abstract class EnumerableExecutor + { + internal abstract object ExecuteBoxed(); + + internal static EnumerableExecutor Create(Expression expression) + { + Type execType = typeof(EnumerableExecutor<>).MakeGenericType(expression.Type); + return (EnumerableExecutor)Activator.CreateInstance(execType, new object[] { expression }); + } + } + + // Must remain public for Silverlight + public class EnumerableExecutor : EnumerableExecutor + { + private Expression _expression; + private Func _func; + + // Must remain public for Silverlight + public EnumerableExecutor(Expression expression) + { + _expression = expression; + } + + internal override object ExecuteBoxed() + { + return this.Execute(); + } + + internal T Execute() + { + if (_func == null) + { + EnumerableRewriter rewriter = new EnumerableRewriter(); + Expression body = rewriter.Visit(_expression); + Expression> f = Expression.Lambda>(body, (IEnumerable)null); + _func = f.Compile(); + } + return _func(); + } + } +} diff --git a/src/System.Linq.Queryable/src/System/Linq/EnumerableQuery.cs b/src/System.Linq.Queryable/src/System/Linq/EnumerableQuery.cs new file mode 100644 index 000000000000..efbc7c6c991a --- /dev/null +++ b/src/System.Linq.Queryable/src/System/Linq/EnumerableQuery.cs @@ -0,0 +1,155 @@ +// Copyright (c) Microsoft. All rights reserved. +// Licensed under the MIT license. See LICENSE file in the project root for full license information. + +using System.Collections; +using System.Collections.Generic; +using System.Linq.Expressions; + +namespace System.Linq +{ + // Must remain public for Silverlight + public abstract class EnumerableQuery + { + internal abstract Expression Expression { get; } + internal abstract IEnumerable Enumerable { get; } + internal static IQueryable Create(Type elementType, IEnumerable sequence) + { + Type seqType = typeof(EnumerableQuery<>).MakeGenericType(elementType); + return (IQueryable)Activator.CreateInstance(seqType, new object[] { sequence }); + } + + internal static IQueryable Create(Type elementType, Expression expression) + { + Type seqType = typeof(EnumerableQuery<>).MakeGenericType(elementType); + return (IQueryable)Activator.CreateInstance(seqType, new object[] { expression }); + } + } + + // Must remain public for Silverlight + public class EnumerableQuery : EnumerableQuery, IOrderedQueryable, IQueryable, IQueryProvider, IEnumerable, IEnumerable + { + private Expression _expression; + private IEnumerable _enumerable; + + IQueryProvider IQueryable.Provider + { + get + { + return (IQueryProvider)this; + } + } + + // Must remain public for Silverlight + public EnumerableQuery(IEnumerable enumerable) + { + _enumerable = enumerable; + _expression = Expression.Constant(this); + } + + // Must remain public for Silverlight + public EnumerableQuery(Expression expression) + { + _expression = expression; + } + + internal override Expression Expression + { + get { return _expression; } + } + + internal override IEnumerable Enumerable + { + get { return _enumerable; } + } + + Expression IQueryable.Expression + { + get { return _expression; } + } + + Type IQueryable.ElementType + { + get { return typeof(T); } + } + + IQueryable IQueryProvider.CreateQuery(Expression expression) + { + if (expression == null) + throw Error.ArgumentNull("expression"); + Type iqType = TypeHelper.FindGenericType(typeof(IQueryable<>), expression.Type); + if (iqType == null) + throw Error.ArgumentNotValid("expression"); + return EnumerableQuery.Create(iqType.GetGenericArguments()[0], expression); + } + + IQueryable IQueryProvider.CreateQuery(Expression expression) + { + if (expression == null) + throw Error.ArgumentNull("expression"); + if (!typeof(IQueryable).IsAssignableFrom(expression.Type)) + { + throw Error.ArgumentNotValid("expression"); + } + return new EnumerableQuery(expression); + } + + // Baselining as Safe for Mix demo so that interface can be transparent. Marking this + // critical (which was the original annotation when porting to silverlight) would violate + // fxcop security rules if the interface isn't also critical. However, transparent code + // can't access this anyway for Mix since we're not exposing AsQueryable(). + // + // Note, the above assertion no longer holds. Now making AsQueryable() public again + // the security fallout of which will need to be re-examined. + object IQueryProvider.Execute(Expression expression) + { + if (expression == null) + throw Error.ArgumentNull("expression"); + Type execType = typeof(EnumerableExecutor<>).MakeGenericType(expression.Type); + return EnumerableExecutor.Create(expression).ExecuteBoxed(); + } + + // see above + S IQueryProvider.Execute(Expression expression) + { + if (expression == null) + throw Error.ArgumentNull("expression"); + if (!typeof(S).IsAssignableFrom(expression.Type)) + throw Error.ArgumentNotValid("expression"); + return new EnumerableExecutor(expression).Execute(); + } + + IEnumerator IEnumerable.GetEnumerator() + { + return this.GetEnumerator(); + } + + IEnumerator IEnumerable.GetEnumerator() + { + return this.GetEnumerator(); + } + + private IEnumerator GetEnumerator() + { + if (_enumerable == null) + { + EnumerableRewriter rewriter = new EnumerableRewriter(); + Expression body = rewriter.Visit(_expression); + Expression>> f = Expression.Lambda>>(body, (IEnumerable)null); + _enumerable = f.Compile()(); + } + return _enumerable.GetEnumerator(); + } + + public override string ToString() + { + ConstantExpression c = _expression as ConstantExpression; + if (c != null && c.Value == this) + { + if (_enumerable != null) + return _enumerable.ToString(); + return "null"; + } + return _expression.ToString(); + } + } +} diff --git a/src/System.Linq.Queryable/src/System/Linq/EnumerableRewriter.cs b/src/System.Linq.Queryable/src/System/Linq/EnumerableRewriter.cs new file mode 100644 index 000000000000..4e95dac9e0a3 --- /dev/null +++ b/src/System.Linq.Queryable/src/System/Linq/EnumerableRewriter.cs @@ -0,0 +1,247 @@ +// Copyright (c) Microsoft. All rights reserved. +// Licensed under the MIT license. See LICENSE file in the project root for full license information. + +using System.Collections; +using System.Collections.Generic; +using System.Collections.ObjectModel; +using System.Linq.Expressions; +using System.Reflection; + +namespace System.Linq +{ + internal class EnumerableRewriter : OldExpressionVisitor + { + internal EnumerableRewriter() + { + } + + internal override Expression VisitMethodCall(MethodCallExpression m) + { + Expression obj = this.Visit(m.Object); + ReadOnlyCollection args = this.VisitExpressionList(m.Arguments); + + // check for args changed + if (obj != m.Object || args != m.Arguments) + { + Expression[] argArray = args.ToArray(); + Type[] typeArgs = (m.Method.IsGenericMethod) ? m.Method.GetGenericArguments() : null; + + if ((m.Method.IsStatic || m.Method.DeclaringType.IsAssignableFrom(obj.Type)) + && ArgsMatch(m.Method, args, typeArgs)) + { + // current method is still valid + return Expression.Call(obj, m.Method, args); + } + else if (m.Method.DeclaringType == typeof(Queryable)) + { + // convert Queryable method to Enumerable method + MethodInfo seqMethod = FindEnumerableMethod(m.Method.Name, args, typeArgs); + args = this.FixupQuotedArgs(seqMethod, args); + return Expression.Call(obj, seqMethod, args); + } + else + { + // rebind to new method + MethodInfo method = FindMethod(m.Method.DeclaringType, m.Method.Name, args, typeArgs); + args = this.FixupQuotedArgs(method, args); + return Expression.Call(obj, method, args); + } + } + return m; + } + + private ReadOnlyCollection FixupQuotedArgs(MethodInfo mi, ReadOnlyCollection argList) + { + ParameterInfo[] pis = mi.GetParameters(); + if (pis.Length > 0) + { + List newArgs = null; + for (int i = 0, n = pis.Length; i < n; i++) + { + Expression arg = argList[i]; + ParameterInfo pi = pis[i]; + arg = FixupQuotedExpression(pi.ParameterType, arg); + if (newArgs == null && arg != argList[i]) + { + newArgs = new List(argList.Count); + for (int j = 0; j < i; j++) + { + newArgs.Add(argList[j]); + } + } + if (newArgs != null) + { + newArgs.Add(arg); + } + } + if (newArgs != null) + argList = newArgs.ToReadOnlyCollection(); + } + return argList; + } + + private Expression FixupQuotedExpression(Type type, Expression expression) + { + Expression expr = expression; + while (true) + { + if (type.IsAssignableFrom(expr.Type)) + return expr; + if (expr.NodeType != ExpressionType.Quote) + break; + expr = ((UnaryExpression)expr).Operand; + } + if (!type.IsAssignableFrom(expr.Type) && type.IsArray && expr.NodeType == ExpressionType.NewArrayInit) + { + Type strippedType = StripExpression(expr.Type); + if (type.IsAssignableFrom(strippedType)) + { + Type elementType = type.GetElementType(); + NewArrayExpression na = (NewArrayExpression)expr; + List exprs = new List(na.Expressions.Count); + for (int i = 0, n = na.Expressions.Count; i < n; i++) + { + exprs.Add(this.FixupQuotedExpression(elementType, na.Expressions[i])); + } + expression = Expression.NewArrayInit(elementType, exprs); + } + } + return expression; + } + + internal override Expression VisitLambda(LambdaExpression lambda) + { + return lambda; + } + + private static Type GetPublicType(Type t) + { + // If we create a constant explicitly typed to be a private nested type, + // such as Lookup<,>.Grouping or a compiler-generated iterator class, then + // we cannot use the expression tree in a context which has only execution + // permissions. We should endeavour to translate constants into + // new constants which have public types. + if (t.GetTypeInfo().IsGenericType && t.GetTypeInfo().GetGenericTypeDefinition().GetTypeInfo().ImplementedInterfaces.Contains(typeof(IGrouping<,>))) + return typeof(IGrouping<,>).MakeGenericType(t.GetGenericArguments()); + if (!t.GetTypeInfo().IsNestedPrivate) + return t; + foreach (Type iType in t.GetTypeInfo().ImplementedInterfaces) + { + if (iType.GetTypeInfo().IsGenericType && iType.GetTypeInfo().GetGenericTypeDefinition() == typeof(IEnumerable<>)) + return iType; + } + if (typeof(IEnumerable).IsAssignableFrom(t)) + return typeof(IEnumerable); + return t; + } + + internal override Expression VisitConstant(ConstantExpression c) + { + EnumerableQuery sq = c.Value as EnumerableQuery; + if (sq != null) + { + if (sq.Enumerable != null) + { + Type t = GetPublicType(sq.Enumerable.GetType()); + return Expression.Constant(sq.Enumerable, t); + } + return this.Visit(sq.Expression); + } + return c; + } + + internal override Expression VisitParameter(ParameterExpression p) + { + return p; + } + + private static volatile ILookup s_seqMethods; + private static MethodInfo FindEnumerableMethod(string name, ReadOnlyCollection args, params Type[] typeArgs) + { + if (s_seqMethods == null) + { + s_seqMethods = typeof(Enumerable).GetStaticMethods().ToLookup(m => m.Name); + } + MethodInfo mi = s_seqMethods[name].FirstOrDefault(m => ArgsMatch(m, args, typeArgs)); + if (mi == null) + throw Error.NoMethodOnTypeMatchingArguments(name, typeof(Enumerable)); + if (typeArgs != null) + return mi.MakeGenericMethod(typeArgs); + return mi; + } + + internal static MethodInfo FindMethod(Type type, string name, ReadOnlyCollection args, Type[] typeArgs) + { + MethodInfo[] methods = type.GetStaticMethods().Where(m => m.Name == name).ToArray(); + if (methods.Length == 0) + throw Error.NoMethodOnType(name, type); + MethodInfo mi = methods.FirstOrDefault(m => ArgsMatch(m, args, typeArgs)); + if (mi == null) + throw Error.NoMethodOnTypeMatchingArguments(name, type); + if (typeArgs != null) + return mi.MakeGenericMethod(typeArgs); + return mi; + } + + private static bool ArgsMatch(MethodInfo m, ReadOnlyCollection args, Type[] typeArgs) + { + ParameterInfo[] mParams = m.GetParameters(); + if (mParams.Length != args.Count) + return false; + if (!m.IsGenericMethod && typeArgs != null && typeArgs.Length > 0) + { + return false; + } + if (!m.IsGenericMethodDefinition && m.IsGenericMethod && m.ContainsGenericParameters) + { + m = m.GetGenericMethodDefinition(); + } + if (m.IsGenericMethodDefinition) + { + if (typeArgs == null || typeArgs.Length == 0) + return false; + if (m.GetGenericArguments().Length != typeArgs.Length) + return false; + m = m.MakeGenericMethod(typeArgs); + mParams = m.GetParameters(); + } + for (int i = 0, n = args.Count; i < n; i++) + { + Type parameterType = mParams[i].ParameterType; + if (parameterType == null) + return false; + if (parameterType.IsByRef) + parameterType = parameterType.GetElementType(); + Expression arg = args[i]; + if (!parameterType.IsAssignableFrom(arg.Type)) + { + if (arg.NodeType == ExpressionType.Quote) + { + arg = ((UnaryExpression)arg).Operand; + } + if (!parameterType.IsAssignableFrom(arg.Type) && + !parameterType.IsAssignableFrom(StripExpression(arg.Type))) + { + return false; + } + } + } + return true; + } + + private static Type StripExpression(Type type) + { + bool isArray = type.IsArray; + Type tmp = isArray ? type.GetElementType() : type; + Type eType = TypeHelper.FindGenericType(typeof(Expression<>), tmp); + if (eType != null) + tmp = eType.GetGenericArguments()[0]; + if (isArray) + { + int rank = type.GetArrayRank(); + return (rank == 1) ? tmp.MakeArrayType() : tmp.MakeArrayType(rank); + } + return type; + } + } +} diff --git a/src/System.Linq.Queryable/src/System/Linq/Error.cs b/src/System.Linq.Queryable/src/System/Linq/Error.cs new file mode 100644 index 000000000000..80f497dfdb85 --- /dev/null +++ b/src/System.Linq.Queryable/src/System/Linq/Error.cs @@ -0,0 +1,48 @@ +// Copyright (c) Microsoft. All rights reserved. +// Licensed under the MIT license. See LICENSE file in the project root for full license information. + +namespace System.Linq +{ + internal class Error + { + internal static Exception ArgumentNull(string message) + { + return new ArgumentNullException(message); + } + + internal static Exception ArgumentNotIEnumerableGeneric(string message) + { + return new ArgumentException(Strings.ArgumentNotIEnumerableGeneric(message)); + } + + internal static Exception ArgumentNotValid(string message) + { + return new ArgumentException(Strings.ArgumentNotValid(message)); + } + + internal static Exception UnhandledExpressionType(object message) + { + return new ArgumentException(Strings.UnhandledExpressionType(message)); + } + + internal static Exception UnhandledBindingType(object message) + { + return new ArgumentException(Strings.UnhandledBindingType(message)); + } + + internal static Exception ArgumentOutOfRange(string message) + { + return new ArgumentOutOfRangeException(message); + } + + internal static Exception NoMethodOnType(string name, object type) + { + return new InvalidOperationException(Strings.NoMethodOnType(name, type)); + } + + internal static Exception NoMethodOnTypeMatchingArguments(string name, object type) + { + return new InvalidOperationException(Strings.NoMethodOnTypeMatchingArguments(name, type)); + } + } +} diff --git a/src/System.Linq.Queryable/src/System/Linq/Expressions/OldExpressionVisitor.cs b/src/System.Linq.Queryable/src/System/Linq/Expressions/OldExpressionVisitor.cs new file mode 100644 index 000000000000..0f2c70c19a65 --- /dev/null +++ b/src/System.Linq.Queryable/src/System/Linq/Expressions/OldExpressionVisitor.cs @@ -0,0 +1,367 @@ +// Copyright (c) Microsoft. All rights reserved. +// Licensed under the MIT license. See LICENSE file in the project root for full license information. + +using System.Collections.Generic; +using System.Collections.ObjectModel; + +namespace System.Linq.Expressions +{ + internal abstract class OldExpressionVisitor + { + internal OldExpressionVisitor() + { + } + + internal virtual Expression Visit(Expression exp) + { + if (exp == null) + return exp; + switch (exp.NodeType) + { + case ExpressionType.UnaryPlus: + case ExpressionType.Negate: + case ExpressionType.NegateChecked: + case ExpressionType.Not: + case ExpressionType.Convert: + case ExpressionType.ConvertChecked: + case ExpressionType.ArrayLength: + case ExpressionType.Quote: + case ExpressionType.TypeAs: + return this.VisitUnary((UnaryExpression)exp); + case ExpressionType.Add: + case ExpressionType.AddChecked: + case ExpressionType.Subtract: + case ExpressionType.SubtractChecked: + case ExpressionType.Multiply: + case ExpressionType.MultiplyChecked: + case ExpressionType.Divide: + case ExpressionType.Modulo: + case ExpressionType.Power: + case ExpressionType.And: + case ExpressionType.AndAlso: + case ExpressionType.Or: + case ExpressionType.OrElse: + case ExpressionType.LessThan: + case ExpressionType.LessThanOrEqual: + case ExpressionType.GreaterThan: + case ExpressionType.GreaterThanOrEqual: + case ExpressionType.Equal: + case ExpressionType.NotEqual: + case ExpressionType.Coalesce: + case ExpressionType.ArrayIndex: + case ExpressionType.RightShift: + case ExpressionType.LeftShift: + case ExpressionType.ExclusiveOr: + return this.VisitBinary((BinaryExpression)exp); + case ExpressionType.TypeIs: + return this.VisitTypeIs((TypeBinaryExpression)exp); + case ExpressionType.Conditional: + return this.VisitConditional((ConditionalExpression)exp); + case ExpressionType.Constant: + return this.VisitConstant((ConstantExpression)exp); + case ExpressionType.Parameter: + return this.VisitParameter((ParameterExpression)exp); + case ExpressionType.MemberAccess: + return this.VisitMemberAccess((MemberExpression)exp); + case ExpressionType.Call: + return this.VisitMethodCall((MethodCallExpression)exp); + case ExpressionType.Lambda: + return this.VisitLambda((LambdaExpression)exp); + case ExpressionType.New: + return this.VisitNew((NewExpression)exp); + case ExpressionType.NewArrayInit: + case ExpressionType.NewArrayBounds: + return this.VisitNewArray((NewArrayExpression)exp); + case ExpressionType.Invoke: + return this.VisitInvocation((InvocationExpression)exp); + case ExpressionType.MemberInit: + return this.VisitMemberInit((MemberInitExpression)exp); + case ExpressionType.ListInit: + return this.VisitListInit((ListInitExpression)exp); + default: + throw Error.UnhandledExpressionType(exp.NodeType); + } + } + + internal virtual MemberBinding VisitBinding(MemberBinding binding) + { + switch (binding.BindingType) + { + case MemberBindingType.Assignment: + return this.VisitMemberAssignment((MemberAssignment)binding); + case MemberBindingType.MemberBinding: + return this.VisitMemberMemberBinding((MemberMemberBinding)binding); + case MemberBindingType.ListBinding: + return this.VisitMemberListBinding((MemberListBinding)binding); + default: + throw Error.UnhandledBindingType(binding.BindingType); + } + } + + internal virtual ElementInit VisitElementInitializer(ElementInit initializer) + { + ReadOnlyCollection arguments = this.VisitExpressionList(initializer.Arguments); + if (arguments != initializer.Arguments) + { + return Expression.ElementInit(initializer.AddMethod, arguments); + } + return initializer; + } + + internal virtual Expression VisitUnary(UnaryExpression u) + { + Expression operand = this.Visit(u.Operand); + if (operand != u.Operand) + { + return Expression.MakeUnary(u.NodeType, operand, u.Type, u.Method); + } + return u; + } + + internal virtual Expression VisitBinary(BinaryExpression b) + { + Expression left = this.Visit(b.Left); + Expression right = this.Visit(b.Right); + Expression conversion = this.Visit(b.Conversion); + if (left != b.Left || right != b.Right || conversion != b.Conversion) + { + if (b.NodeType == ExpressionType.Coalesce && b.Conversion != null) + return Expression.Coalesce(left, right, conversion as LambdaExpression); + else + return Expression.MakeBinary(b.NodeType, left, right, b.IsLiftedToNull, b.Method); + } + return b; + } + + internal virtual Expression VisitTypeIs(TypeBinaryExpression b) + { + Expression expr = this.Visit(b.Expression); + if (expr != b.Expression) + { + return Expression.TypeIs(expr, b.TypeOperand); + } + return b; + } + + internal virtual Expression VisitConstant(ConstantExpression c) + { + return c; + } + + internal virtual Expression VisitConditional(ConditionalExpression c) + { + Expression test = this.Visit(c.Test); + Expression ifTrue = this.Visit(c.IfTrue); + Expression ifFalse = this.Visit(c.IfFalse); + if (test != c.Test || ifTrue != c.IfTrue || ifFalse != c.IfFalse) + { + return Expression.Condition(test, ifTrue, ifFalse); + } + return c; + } + + internal virtual Expression VisitParameter(ParameterExpression p) + { + return p; + } + + internal virtual Expression VisitMemberAccess(MemberExpression m) + { + Expression exp = this.Visit(m.Expression); + if (exp != m.Expression) + { + return Expression.MakeMemberAccess(exp, m.Member); + } + return m; + } + + internal virtual Expression VisitMethodCall(MethodCallExpression m) + { + Expression obj = this.Visit(m.Object); + IEnumerable args = this.VisitExpressionList(m.Arguments); + if (obj != m.Object || args != m.Arguments) + { + return Expression.Call(obj, m.Method, args); + } + return m; + } + + internal virtual ReadOnlyCollection VisitExpressionList(ReadOnlyCollection original) + { + List list = null; + for (int i = 0, n = original.Count; i < n; i++) + { + Expression p = this.Visit(original[i]); + if (list != null) + { + list.Add(p); + } + else if (p != original[i]) + { + list = new List(n); + for (int j = 0; j < i; j++) + { + list.Add(original[j]); + } + list.Add(p); + } + } + if (list != null) + return list.ToReadOnlyCollection(); + return original; + } + + internal virtual MemberAssignment VisitMemberAssignment(MemberAssignment assignment) + { + Expression e = this.Visit(assignment.Expression); + if (e != assignment.Expression) + { + return Expression.Bind(assignment.Member, e); + } + return assignment; + } + + internal virtual MemberMemberBinding VisitMemberMemberBinding(MemberMemberBinding binding) + { + IEnumerable bindings = this.VisitBindingList(binding.Bindings); + if (bindings != binding.Bindings) + { + return Expression.MemberBind(binding.Member, bindings); + } + return binding; + } + + internal virtual MemberListBinding VisitMemberListBinding(MemberListBinding binding) + { + IEnumerable initializers = this.VisitElementInitializerList(binding.Initializers); + if (initializers != binding.Initializers) + { + return Expression.ListBind(binding.Member, initializers); + } + return binding; + } + + internal virtual IEnumerable VisitBindingList(ReadOnlyCollection original) + { + List list = null; + for (int i = 0, n = original.Count; i < n; i++) + { + MemberBinding b = this.VisitBinding(original[i]); + if (list != null) + { + list.Add(b); + } + else if (b != original[i]) + { + list = new List(n); + for (int j = 0; j < i; j++) + { + list.Add(original[j]); + } + list.Add(b); + } + } + if (list != null) + return list; + return original; + } + + internal virtual IEnumerable VisitElementInitializerList(ReadOnlyCollection original) + { + List list = null; + for (int i = 0, n = original.Count; i < n; i++) + { + ElementInit init = this.VisitElementInitializer(original[i]); + if (list != null) + { + list.Add(init); + } + else if (init != original[i]) + { + list = new List(n); + for (int j = 0; j < i; j++) + { + list.Add(original[j]); + } + list.Add(init); + } + } + if (list != null) + return list; + return original; + } + + internal virtual Expression VisitLambda(LambdaExpression lambda) + { + Expression body = this.Visit(lambda.Body); + if (body != lambda.Body) + { + return Expression.Lambda(lambda.Type, body, lambda.Parameters); + } + return lambda; + } + + internal virtual NewExpression VisitNew(NewExpression nex) + { + IEnumerable args = this.VisitExpressionList(nex.Arguments); + if (args != nex.Arguments) + { + if (nex.Members != null) + return Expression.New(nex.Constructor, args, nex.Members); + else + return Expression.New(nex.Constructor, args); + } + return nex; + } + + internal virtual Expression VisitMemberInit(MemberInitExpression init) + { + NewExpression n = this.VisitNew(init.NewExpression); + IEnumerable bindings = this.VisitBindingList(init.Bindings); + if (n != init.NewExpression || bindings != init.Bindings) + { + return Expression.MemberInit(n, bindings); + } + return init; + } + + internal virtual Expression VisitListInit(ListInitExpression init) + { + NewExpression n = this.VisitNew(init.NewExpression); + IEnumerable initializers = this.VisitElementInitializerList(init.Initializers); + if (n != init.NewExpression || initializers != init.Initializers) + { + return Expression.ListInit(n, initializers); + } + return init; + } + + internal virtual Expression VisitNewArray(NewArrayExpression na) + { + IEnumerable exprs = this.VisitExpressionList(na.Expressions); + if (exprs != na.Expressions) + { + if (na.NodeType == ExpressionType.NewArrayInit) + { + return Expression.NewArrayInit(na.Type.GetElementType(), exprs); + } + else + { + return Expression.NewArrayBounds(na.Type.GetElementType(), exprs); + } + } + return na; + } + + internal virtual Expression VisitInvocation(InvocationExpression iv) + { + IEnumerable args = this.VisitExpressionList(iv.Arguments); + Expression expr = this.Visit(iv.Expression); + if (args != iv.Arguments || expr != iv.Expression) + { + return Expression.Invoke(expr, args); + } + return iv; + } + } +} diff --git a/src/System.Linq.Queryable/src/System/Linq/Expressions/ReadOnlyCollectionExtensions.cs b/src/System.Linq.Queryable/src/System/Linq/Expressions/ReadOnlyCollectionExtensions.cs new file mode 100644 index 000000000000..44995fa1dfc2 --- /dev/null +++ b/src/System.Linq.Queryable/src/System/Linq/Expressions/ReadOnlyCollectionExtensions.cs @@ -0,0 +1,34 @@ +// Copyright (c) Microsoft. All rights reserved. +// Licensed under the MIT license. See LICENSE file in the project root for full license information. + +using System.Collections.Generic; +using System.Collections.ObjectModel; + +namespace System.Linq.Expressions +{ + internal static class ReadOnlyCollectionExtensions + { + internal static ReadOnlyCollection ToReadOnlyCollection(this IEnumerable sequence) + { + if (sequence == null) + return DefaultReadOnlyCollection.Empty; + ReadOnlyCollection col = sequence as ReadOnlyCollection; + if (col != null) + return col; + return new ReadOnlyCollection(sequence.ToArray()); + } + private static class DefaultReadOnlyCollection + { + private static volatile ReadOnlyCollection s_defaultCollection; + internal static ReadOnlyCollection Empty + { + get + { + if (s_defaultCollection == null) + s_defaultCollection = new ReadOnlyCollection(new T[] { }); + return s_defaultCollection; + } + } + } + } +} diff --git a/src/System.Linq.Queryable/src/System/Linq/Queryable.cs b/src/System.Linq.Queryable/src/System/Linq/Queryable.cs new file mode 100644 index 000000000000..50936a4994b1 --- /dev/null +++ b/src/System.Linq.Queryable/src/System/Linq/Queryable.cs @@ -0,0 +1,1743 @@ +// Copyright (c) Microsoft. All rights reserved. +// Licensed under the MIT license. See LICENSE file in the project root for full license information. + +using System.Collections; +using System.Collections.Generic; +using System.Linq.Expressions; +using System.Reflection; + +namespace System.Linq +{ + public static class Queryable + { + public static IQueryable AsQueryable(this IEnumerable source) + { + if (source == null) + throw Error.ArgumentNull("source"); + if (source is IQueryable) + return (IQueryable)source; + return new EnumerableQuery(source); + } + + public static IQueryable AsQueryable(this IEnumerable source) + { + if (source == null) + throw Error.ArgumentNull("source"); + if (source is IQueryable) + return (IQueryable)source; + Type enumType = TypeHelper.FindGenericType(typeof(IEnumerable<>), source.GetType()); + if (enumType == null) + throw Error.ArgumentNotIEnumerableGeneric("source"); + return EnumerableQuery.Create(enumType.GetTypeInfo().GenericTypeArguments[0], source); + } + + public static IQueryable Where(this IQueryable source, Expression> predicate) + { + if (source == null) + throw Error.ArgumentNull("source"); + if (predicate == null) + throw Error.ArgumentNull("predicate"); + return source.Provider.CreateQuery( + Expression.Call( + null, + GetMethodInfoOf(() => Queryable.Where(source, predicate)), + new Expression[] { source.Expression, Expression.Quote(predicate) } + )); + } + + public static IQueryable Where(this IQueryable source, Expression> predicate) + { + if (source == null) + throw Error.ArgumentNull("source"); + if (predicate == null) + throw Error.ArgumentNull("predicate"); + return source.Provider.CreateQuery( + Expression.Call( + null, + GetMethodInfoOf(() => Queryable.Where(source, predicate)), + new Expression[] { source.Expression, Expression.Quote(predicate) } + )); + } + + public static IQueryable OfType(this IQueryable source) + { + if (source == null) + throw Error.ArgumentNull("source"); + return source.Provider.CreateQuery( + Expression.Call( + null, + GetMethodInfoOf(() => Queryable.OfType(source)), + new Expression[] { source.Expression } + )); + } + + public static IQueryable Cast(this IQueryable source) + { + if (source == null) + throw Error.ArgumentNull("source"); + return source.Provider.CreateQuery( + Expression.Call( + null, + GetMethodInfoOf(() => Queryable.Cast(source)), + new Expression[] { source.Expression } + )); + } + + public static IQueryable Select(this IQueryable source, Expression> selector) + { + if (source == null) + throw Error.ArgumentNull("source"); + if (selector == null) + throw Error.ArgumentNull("selector"); + return source.Provider.CreateQuery( + Expression.Call( + null, + GetMethodInfoOf(() => Queryable.Select(source, selector)), + new Expression[] { source.Expression, Expression.Quote(selector) } + )); + } + + public static IQueryable Select(this IQueryable source, Expression> selector) + { + if (source == null) + throw Error.ArgumentNull("source"); + if (selector == null) + throw Error.ArgumentNull("selector"); + return source.Provider.CreateQuery( + Expression.Call( + null, + GetMethodInfoOf(() => Queryable.Select(source, selector)), + new Expression[] { source.Expression, Expression.Quote(selector) } + )); + } + + public static IQueryable SelectMany(this IQueryable source, Expression>> selector) + { + if (source == null) + throw Error.ArgumentNull("source"); + if (selector == null) + throw Error.ArgumentNull("selector"); + return source.Provider.CreateQuery( + Expression.Call( + null, + GetMethodInfoOf(() => Queryable.SelectMany(source, selector)), + new Expression[] { source.Expression, Expression.Quote(selector) } + )); + } + + public static IQueryable SelectMany(this IQueryable source, Expression>> selector) + { + if (source == null) + throw Error.ArgumentNull("source"); + if (selector == null) + throw Error.ArgumentNull("selector"); + return source.Provider.CreateQuery( + Expression.Call( + null, + GetMethodInfoOf(() => Queryable.SelectMany(source, selector)), + new Expression[] { source.Expression, Expression.Quote(selector) } + )); + } + + public static IQueryable SelectMany(this IQueryable source, Expression>> collectionSelector, Expression> resultSelector) + { + if (source == null) + throw Error.ArgumentNull("source"); + if (collectionSelector == null) + throw Error.ArgumentNull("collectionSelector"); + if (resultSelector == null) + throw Error.ArgumentNull("resultSelector"); + return source.Provider.CreateQuery( + Expression.Call( + null, + GetMethodInfoOf(() => Queryable.SelectMany(source, collectionSelector, resultSelector)), + new Expression[] { source.Expression, Expression.Quote(collectionSelector), Expression.Quote(resultSelector) } + )); + } + + public static IQueryable SelectMany(this IQueryable source, Expression>> collectionSelector, Expression> resultSelector) + { + if (source == null) + throw Error.ArgumentNull("source"); + if (collectionSelector == null) + throw Error.ArgumentNull("collectionSelector"); + if (resultSelector == null) + throw Error.ArgumentNull("resultSelector"); + return source.Provider.CreateQuery( + Expression.Call( + null, + GetMethodInfoOf(() => Queryable.SelectMany(source, collectionSelector, resultSelector)), + new Expression[] { source.Expression, Expression.Quote(collectionSelector), Expression.Quote(resultSelector) } + )); + } + + private static Expression GetSourceExpression(IEnumerable source) + { + IQueryable q = source as IQueryable; + if (q != null) return q.Expression; + return Expression.Constant(source, typeof(IEnumerable)); + } + + public static IQueryable Join(this IQueryable outer, IEnumerable inner, Expression> outerKeySelector, Expression> innerKeySelector, Expression> resultSelector) + { + if (outer == null) + throw Error.ArgumentNull("outer"); + if (inner == null) + throw Error.ArgumentNull("inner"); + if (outerKeySelector == null) + throw Error.ArgumentNull("outerKeySelector"); + if (innerKeySelector == null) + throw Error.ArgumentNull("innerKeySelector"); + if (resultSelector == null) + throw Error.ArgumentNull("resultSelector"); + return outer.Provider.CreateQuery( + Expression.Call( + null, + GetMethodInfoOf(() => Queryable.Join(outer, inner, outerKeySelector, innerKeySelector, resultSelector)), + new Expression[] { + outer.Expression, + GetSourceExpression(inner), + Expression.Quote(outerKeySelector), + Expression.Quote(innerKeySelector), + Expression.Quote(resultSelector) + } + )); + } + + public static IQueryable Join(this IQueryable outer, IEnumerable inner, Expression> outerKeySelector, Expression> innerKeySelector, Expression> resultSelector, IEqualityComparer comparer) + { + if (outer == null) + throw Error.ArgumentNull("outer"); + if (inner == null) + throw Error.ArgumentNull("inner"); + if (outerKeySelector == null) + throw Error.ArgumentNull("outerKeySelector"); + if (innerKeySelector == null) + throw Error.ArgumentNull("innerKeySelector"); + if (resultSelector == null) + throw Error.ArgumentNull("resultSelector"); + return outer.Provider.CreateQuery( + Expression.Call( + null, + GetMethodInfoOf(() => Queryable.Join(outer, inner, outerKeySelector, innerKeySelector, resultSelector, comparer)), + new Expression[] { + outer.Expression, + GetSourceExpression(inner), + Expression.Quote(outerKeySelector), + Expression.Quote(innerKeySelector), + Expression.Quote(resultSelector), + Expression.Constant(comparer, typeof(IEqualityComparer)) + } + )); + } + + public static IQueryable GroupJoin(this IQueryable outer, IEnumerable inner, Expression> outerKeySelector, Expression> innerKeySelector, Expression, TResult>> resultSelector) + { + if (outer == null) + throw Error.ArgumentNull("outer"); + if (inner == null) + throw Error.ArgumentNull("inner"); + if (outerKeySelector == null) + throw Error.ArgumentNull("outerKeySelector"); + if (innerKeySelector == null) + throw Error.ArgumentNull("innerKeySelector"); + if (resultSelector == null) + throw Error.ArgumentNull("resultSelector"); + return outer.Provider.CreateQuery( + Expression.Call( + null, + GetMethodInfoOf(() => Queryable.GroupJoin(outer, inner, outerKeySelector, innerKeySelector, resultSelector)), + new Expression[] { + outer.Expression, + GetSourceExpression(inner), + Expression.Quote(outerKeySelector), + Expression.Quote(innerKeySelector), + Expression.Quote(resultSelector) } + )); + } + + public static IQueryable GroupJoin(this IQueryable outer, IEnumerable inner, Expression> outerKeySelector, Expression> innerKeySelector, Expression, TResult>> resultSelector, IEqualityComparer comparer) + { + if (outer == null) + throw Error.ArgumentNull("outer"); + if (inner == null) + throw Error.ArgumentNull("inner"); + if (outerKeySelector == null) + throw Error.ArgumentNull("outerKeySelector"); + if (innerKeySelector == null) + throw Error.ArgumentNull("innerKeySelector"); + if (resultSelector == null) + throw Error.ArgumentNull("resultSelector"); + return outer.Provider.CreateQuery( + Expression.Call( + null, + GetMethodInfoOf(() => Queryable.GroupJoin(outer, inner, outerKeySelector, innerKeySelector, resultSelector, comparer)), + new Expression[] { + outer.Expression, + GetSourceExpression(inner), + Expression.Quote(outerKeySelector), + Expression.Quote(innerKeySelector), + Expression.Quote(resultSelector), + Expression.Constant(comparer, typeof(IEqualityComparer)) } + )); + } + + public static IOrderedQueryable OrderBy(this IQueryable source, Expression> keySelector) + { + if (source == null) + throw Error.ArgumentNull("source"); + if (keySelector == null) + throw Error.ArgumentNull("keySelector"); + return (IOrderedQueryable)source.Provider.CreateQuery( + Expression.Call( + null, + GetMethodInfoOf(() => Queryable.OrderBy(source, keySelector)), + new Expression[] { source.Expression, Expression.Quote(keySelector) } + )); + } + + public static IOrderedQueryable OrderBy(this IQueryable source, Expression> keySelector, IComparer comparer) + { + if (source == null) + throw Error.ArgumentNull("source"); + if (keySelector == null) + throw Error.ArgumentNull("keySelector"); + return (IOrderedQueryable)source.Provider.CreateQuery( + Expression.Call( + null, + GetMethodInfoOf(() => Queryable.OrderBy(source, keySelector, comparer)), + new Expression[] { source.Expression, Expression.Quote(keySelector), Expression.Constant(comparer, typeof(IComparer)) } + )); + } + + public static IOrderedQueryable OrderByDescending(this IQueryable source, Expression> keySelector) + { + if (source == null) + throw Error.ArgumentNull("source"); + if (keySelector == null) + throw Error.ArgumentNull("keySelector"); + return (IOrderedQueryable)source.Provider.CreateQuery( + Expression.Call( + null, + GetMethodInfoOf(() => Queryable.OrderByDescending(source, keySelector)), + new Expression[] { source.Expression, Expression.Quote(keySelector) } + )); + } + + public static IOrderedQueryable OrderByDescending(this IQueryable source, Expression> keySelector, IComparer comparer) + { + if (source == null) + throw Error.ArgumentNull("source"); + if (keySelector == null) + throw Error.ArgumentNull("keySelector"); + return (IOrderedQueryable)source.Provider.CreateQuery( + Expression.Call( + null, + GetMethodInfoOf(() => Queryable.OrderByDescending(source, keySelector, comparer)), + new Expression[] { source.Expression, Expression.Quote(keySelector), Expression.Constant(comparer, typeof(IComparer)) } + )); + } + + public static IOrderedQueryable ThenBy(this IOrderedQueryable source, Expression> keySelector) + { + if (source == null) + throw Error.ArgumentNull("source"); + if (keySelector == null) + throw Error.ArgumentNull("keySelector"); + return (IOrderedQueryable)source.Provider.CreateQuery( + Expression.Call( + null, + GetMethodInfoOf(() => Queryable.ThenBy(source, keySelector)), + new Expression[] { source.Expression, Expression.Quote(keySelector) } + )); + } + + public static IOrderedQueryable ThenBy(this IOrderedQueryable source, Expression> keySelector, IComparer comparer) + { + if (source == null) + throw Error.ArgumentNull("source"); + if (keySelector == null) + throw Error.ArgumentNull("keySelector"); + return (IOrderedQueryable)source.Provider.CreateQuery( + Expression.Call( + null, + GetMethodInfoOf(() => Queryable.ThenBy(source, keySelector, comparer)), + new Expression[] { source.Expression, Expression.Quote(keySelector), Expression.Constant(comparer, typeof(IComparer)) } + )); + } + + public static IOrderedQueryable ThenByDescending(this IOrderedQueryable source, Expression> keySelector) + { + if (source == null) + throw Error.ArgumentNull("source"); + if (keySelector == null) + throw Error.ArgumentNull("keySelector"); + return (IOrderedQueryable)source.Provider.CreateQuery( + Expression.Call( + null, + GetMethodInfoOf(() => Queryable.ThenByDescending(source, keySelector)), + new Expression[] { source.Expression, Expression.Quote(keySelector) } + )); + } + + public static IOrderedQueryable ThenByDescending(this IOrderedQueryable source, Expression> keySelector, IComparer comparer) + { + if (source == null) + throw Error.ArgumentNull("source"); + if (keySelector == null) + throw Error.ArgumentNull("keySelector"); + return (IOrderedQueryable)source.Provider.CreateQuery( + Expression.Call( + null, + GetMethodInfoOf(() => Queryable.ThenByDescending(source, keySelector, comparer)), + new Expression[] { source.Expression, Expression.Quote(keySelector), Expression.Constant(comparer, typeof(IComparer)) } + )); + } + + public static IQueryable Take(this IQueryable source, int count) + { + if (source == null) + throw Error.ArgumentNull("source"); + return source.Provider.CreateQuery( + Expression.Call( + null, + GetMethodInfoOf(() => Queryable.Take(source, count)), + new Expression[] { source.Expression, Expression.Constant(count) } + )); + } + + public static IQueryable TakeWhile(this IQueryable source, Expression> predicate) + { + if (source == null) + throw Error.ArgumentNull("source"); + if (predicate == null) + throw Error.ArgumentNull("predicate"); + return source.Provider.CreateQuery( + Expression.Call( + null, + GetMethodInfoOf(() => Queryable.TakeWhile(source, predicate)), + new Expression[] { source.Expression, Expression.Quote(predicate) } + )); + } + + public static IQueryable TakeWhile(this IQueryable source, Expression> predicate) + { + if (source == null) + throw Error.ArgumentNull("source"); + if (predicate == null) + throw Error.ArgumentNull("predicate"); + return source.Provider.CreateQuery( + Expression.Call( + null, + GetMethodInfoOf(() => Queryable.TakeWhile(source, predicate)), + new Expression[] { source.Expression, Expression.Quote(predicate) } + )); + } + + public static IQueryable Skip(this IQueryable source, int count) + { + if (source == null) + throw Error.ArgumentNull("source"); + return source.Provider.CreateQuery( + Expression.Call( + null, + GetMethodInfoOf(() => Queryable.Skip(source, count)), + new Expression[] { source.Expression, Expression.Constant(count) } + )); + } + + public static IQueryable SkipWhile(this IQueryable source, Expression> predicate) + { + if (source == null) + throw Error.ArgumentNull("source"); + if (predicate == null) + throw Error.ArgumentNull("predicate"); + return source.Provider.CreateQuery( + Expression.Call( + null, + GetMethodInfoOf(() => Queryable.SkipWhile(source, predicate)), + new Expression[] { source.Expression, Expression.Quote(predicate) } + )); + } + + public static IQueryable SkipWhile(this IQueryable source, Expression> predicate) + { + if (source == null) + throw Error.ArgumentNull("source"); + if (predicate == null) + throw Error.ArgumentNull("predicate"); + return source.Provider.CreateQuery( + Expression.Call( + null, + GetMethodInfoOf(() => Queryable.SkipWhile(source, predicate)), + new Expression[] { source.Expression, Expression.Quote(predicate) } + )); + } + + public static IQueryable> GroupBy(this IQueryable source, Expression> keySelector) + { + if (source == null) + throw Error.ArgumentNull("source"); + if (keySelector == null) + throw Error.ArgumentNull("keySelector"); + return source.Provider.CreateQuery>( + Expression.Call( + null, + GetMethodInfoOf(() => Queryable.GroupBy(source, keySelector)), + new Expression[] { source.Expression, Expression.Quote(keySelector) } + )); + } + + public static IQueryable> GroupBy(this IQueryable source, Expression> keySelector, Expression> elementSelector) + { + if (source == null) + throw Error.ArgumentNull("source"); + if (keySelector == null) + throw Error.ArgumentNull("keySelector"); + if (elementSelector == null) + throw Error.ArgumentNull("elementSelector"); + return source.Provider.CreateQuery>( + Expression.Call( + null, + GetMethodInfoOf(() => Queryable.GroupBy(source, keySelector, elementSelector)), + new Expression[] { source.Expression, Expression.Quote(keySelector), Expression.Quote(elementSelector) } + )); + } + + public static IQueryable> GroupBy(this IQueryable source, Expression> keySelector, IEqualityComparer comparer) + { + if (source == null) + throw Error.ArgumentNull("source"); + if (keySelector == null) + throw Error.ArgumentNull("keySelector"); + return source.Provider.CreateQuery>( + Expression.Call( + null, + GetMethodInfoOf(() => Queryable.GroupBy(source, keySelector, comparer)), + new Expression[] { source.Expression, Expression.Quote(keySelector), Expression.Constant(comparer, typeof(IEqualityComparer)) } + )); + } + + public static IQueryable> GroupBy(this IQueryable source, Expression> keySelector, Expression> elementSelector, IEqualityComparer comparer) + { + if (source == null) + throw Error.ArgumentNull("source"); + if (keySelector == null) + throw Error.ArgumentNull("keySelector"); + if (elementSelector == null) + throw Error.ArgumentNull("elementSelector"); + return source.Provider.CreateQuery>( + Expression.Call( + null, + GetMethodInfoOf(() => Queryable.GroupBy(source, keySelector, elementSelector, comparer)), + new Expression[] { source.Expression, Expression.Quote(keySelector), Expression.Quote(elementSelector), Expression.Constant(comparer, typeof(IEqualityComparer)) } + )); + } + + public static IQueryable GroupBy(this IQueryable source, Expression> keySelector, Expression> elementSelector, Expression, TResult>> resultSelector) + { + if (source == null) + throw Error.ArgumentNull("source"); + if (keySelector == null) + throw Error.ArgumentNull("keySelector"); + if (elementSelector == null) + throw Error.ArgumentNull("elementSelector"); + if (resultSelector == null) + throw Error.ArgumentNull("resultSelector"); + return source.Provider.CreateQuery( + Expression.Call( + null, + GetMethodInfoOf(() => Queryable.GroupBy(source, keySelector, elementSelector, resultSelector)), + new Expression[] { source.Expression, Expression.Quote(keySelector), Expression.Quote(elementSelector), Expression.Quote(resultSelector) } + )); + } + + public static IQueryable GroupBy(this IQueryable source, Expression> keySelector, Expression, TResult>> resultSelector) + { + if (source == null) + throw Error.ArgumentNull("source"); + if (keySelector == null) + throw Error.ArgumentNull("keySelector"); + if (resultSelector == null) + throw Error.ArgumentNull("resultSelector"); + return source.Provider.CreateQuery( + Expression.Call( + null, + GetMethodInfoOf(() => Queryable.GroupBy(source, keySelector, resultSelector)), + new Expression[] { source.Expression, Expression.Quote(keySelector), Expression.Quote(resultSelector) } + )); + } + + public static IQueryable GroupBy(this IQueryable source, Expression> keySelector, Expression, TResult>> resultSelector, IEqualityComparer comparer) + { + if (source == null) + throw Error.ArgumentNull("source"); + if (keySelector == null) + throw Error.ArgumentNull("keySelector"); + if (resultSelector == null) + throw Error.ArgumentNull("resultSelector"); + return source.Provider.CreateQuery( + Expression.Call( + null, + GetMethodInfoOf(() => Queryable.GroupBy(source, keySelector, resultSelector, comparer)), + new Expression[] { source.Expression, Expression.Quote(keySelector), Expression.Quote(resultSelector), Expression.Constant(comparer, typeof(IEqualityComparer)) } + )); + } + + public static IQueryable GroupBy(this IQueryable source, Expression> keySelector, Expression> elementSelector, Expression, TResult>> resultSelector, IEqualityComparer comparer) + { + if (source == null) + throw Error.ArgumentNull("source"); + if (keySelector == null) + throw Error.ArgumentNull("keySelector"); + if (elementSelector == null) + throw Error.ArgumentNull("elementSelector"); + if (resultSelector == null) + throw Error.ArgumentNull("resultSelector"); + return source.Provider.CreateQuery( + Expression.Call( + null, + GetMethodInfoOf(() => Queryable.GroupBy(source, keySelector, elementSelector, resultSelector, comparer)), + new Expression[] { source.Expression, Expression.Quote(keySelector), Expression.Quote(elementSelector), Expression.Quote(resultSelector), Expression.Constant(comparer, typeof(IEqualityComparer)) } + )); + } + + public static IQueryable Distinct(this IQueryable source) + { + if (source == null) + throw Error.ArgumentNull("source"); + return source.Provider.CreateQuery( + Expression.Call( + null, + GetMethodInfoOf(() => Queryable.Distinct(source)), + new Expression[] { source.Expression } + )); + } + + public static IQueryable Distinct(this IQueryable source, IEqualityComparer comparer) + { + if (source == null) + throw Error.ArgumentNull("source"); + return source.Provider.CreateQuery( + Expression.Call( + null, + GetMethodInfoOf(() => Queryable.Distinct(source, comparer)), + new Expression[] { source.Expression, Expression.Constant(comparer, typeof(IEqualityComparer)) } + )); + } + + public static IQueryable Concat(this IQueryable source1, IEnumerable source2) + { + if (source1 == null) + throw Error.ArgumentNull("source1"); + if (source2 == null) + throw Error.ArgumentNull("source2"); + return source1.Provider.CreateQuery( + Expression.Call( + null, + GetMethodInfoOf(() => Queryable.Concat(source1, source2)), + new Expression[] { source1.Expression, GetSourceExpression(source2) } + )); + } + + public static IQueryable Zip(this IQueryable source1, IEnumerable source2, Expression> resultSelector) + { + if (source1 == null) + throw Error.ArgumentNull("source1"); + if (source2 == null) + throw Error.ArgumentNull("source2"); + if (resultSelector == null) + throw Error.ArgumentNull("resultSelector"); + return source1.Provider.CreateQuery( + Expression.Call( + null, + GetMethodInfoOf(() => Queryable.Zip(source1, source2, resultSelector)), + new Expression[] { source1.Expression, GetSourceExpression(source2), Expression.Quote(resultSelector) } + )); + } + + public static IQueryable Union(this IQueryable source1, IEnumerable source2) + { + if (source1 == null) + throw Error.ArgumentNull("source1"); + if (source2 == null) + throw Error.ArgumentNull("source2"); + return source1.Provider.CreateQuery( + Expression.Call( + null, + GetMethodInfoOf(() => Queryable.Union(source1, source2)), + new Expression[] { source1.Expression, GetSourceExpression(source2) } + )); + } + + public static IQueryable Union(this IQueryable source1, IEnumerable source2, IEqualityComparer comparer) + { + if (source1 == null) + throw Error.ArgumentNull("source1"); + if (source2 == null) + throw Error.ArgumentNull("source2"); + return source1.Provider.CreateQuery( + Expression.Call( + null, + GetMethodInfoOf(() => Queryable.Union(source1, source2, comparer)), + new Expression[] { + source1.Expression, + GetSourceExpression(source2), + Expression.Constant(comparer, typeof(IEqualityComparer)) + } + )); + } + + public static IQueryable Intersect(this IQueryable source1, IEnumerable source2) + { + if (source1 == null) + throw Error.ArgumentNull("source1"); + if (source2 == null) + throw Error.ArgumentNull("source2"); + return source1.Provider.CreateQuery( + Expression.Call( + null, + GetMethodInfoOf(() => Queryable.Intersect(source1, source2)), + new Expression[] { source1.Expression, GetSourceExpression(source2) } + )); + } + + public static IQueryable Intersect(this IQueryable source1, IEnumerable source2, IEqualityComparer comparer) + { + if (source1 == null) + throw Error.ArgumentNull("source1"); + if (source2 == null) + throw Error.ArgumentNull("source2"); + return source1.Provider.CreateQuery( + Expression.Call( + null, + GetMethodInfoOf(() => Queryable.Intersect(source1, source2, comparer)), + new Expression[] { + source1.Expression, + GetSourceExpression(source2), + Expression.Constant(comparer, typeof(IEqualityComparer)) + } + )); + } + + public static IQueryable Except(this IQueryable source1, IEnumerable source2) + { + if (source1 == null) + throw Error.ArgumentNull("source1"); + if (source2 == null) + throw Error.ArgumentNull("source2"); + return source1.Provider.CreateQuery( + Expression.Call( + null, + GetMethodInfoOf(() => Queryable.Except(source1, source2)), + new Expression[] { source1.Expression, GetSourceExpression(source2) } + )); + } + + public static IQueryable Except(this IQueryable source1, IEnumerable source2, IEqualityComparer comparer) + { + if (source1 == null) + throw Error.ArgumentNull("source1"); + if (source2 == null) + throw Error.ArgumentNull("source2"); + return source1.Provider.CreateQuery( + Expression.Call( + null, + GetMethodInfoOf(() => Queryable.Except(source1, source2, comparer)), + new Expression[] { + source1.Expression, + GetSourceExpression(source2), + Expression.Constant(comparer, typeof(IEqualityComparer)) + } + )); + } + + public static TSource First(this IQueryable source) + { + if (source == null) + throw Error.ArgumentNull("source"); + return source.Provider.Execute( + Expression.Call( + null, + GetMethodInfoOf(() => Queryable.First(source)), + new Expression[] { source.Expression } + )); + } + + public static TSource First(this IQueryable source, Expression> predicate) + { + if (source == null) + throw Error.ArgumentNull("source"); + if (predicate == null) + throw Error.ArgumentNull("predicate"); + return source.Provider.Execute( + Expression.Call( + null, + GetMethodInfoOf(() => Queryable.First(source, predicate)), + new Expression[] { source.Expression, Expression.Quote(predicate) } + )); + } + + public static TSource FirstOrDefault(this IQueryable source) + { + if (source == null) + throw Error.ArgumentNull("source"); + return source.Provider.Execute( + Expression.Call( + null, + GetMethodInfoOf(() => Queryable.FirstOrDefault(source)), + new Expression[] { source.Expression } + )); + } + + public static TSource FirstOrDefault(this IQueryable source, Expression> predicate) + { + if (source == null) + throw Error.ArgumentNull("source"); + if (predicate == null) + throw Error.ArgumentNull("predicate"); + return source.Provider.Execute( + Expression.Call( + null, + GetMethodInfoOf(() => Queryable.FirstOrDefault(source, predicate)), + new Expression[] { source.Expression, Expression.Quote(predicate) } + )); + } + + public static TSource Last(this IQueryable source) + { + if (source == null) + throw Error.ArgumentNull("source"); + return source.Provider.Execute( + Expression.Call( + null, + GetMethodInfoOf(() => Queryable.Last(source)), + new Expression[] { source.Expression } + )); + } + + public static TSource Last(this IQueryable source, Expression> predicate) + { + if (source == null) + throw Error.ArgumentNull("source"); + if (predicate == null) + throw Error.ArgumentNull("predicate"); + return source.Provider.Execute( + Expression.Call( + null, + GetMethodInfoOf(() => Queryable.Last(source, predicate)), + new Expression[] { source.Expression, Expression.Quote(predicate) } + )); + } + + public static TSource LastOrDefault(this IQueryable source) + { + if (source == null) + throw Error.ArgumentNull("source"); + return source.Provider.Execute( + Expression.Call( + null, + GetMethodInfoOf(() => Queryable.LastOrDefault(source)), + new Expression[] { source.Expression } + )); + } + + public static TSource LastOrDefault(this IQueryable source, Expression> predicate) + { + if (source == null) + throw Error.ArgumentNull("source"); + if (predicate == null) + throw Error.ArgumentNull("predicate"); + return source.Provider.Execute( + Expression.Call( + null, + GetMethodInfoOf(() => Queryable.LastOrDefault(source, predicate)), + new Expression[] { source.Expression, Expression.Quote(predicate) } + )); + } + + public static TSource Single(this IQueryable source) + { + if (source == null) + throw Error.ArgumentNull("source"); + return source.Provider.Execute( + Expression.Call( + null, + GetMethodInfoOf(() => Queryable.Single(source)), + new Expression[] { source.Expression } + )); + } + + public static TSource Single(this IQueryable source, Expression> predicate) + { + if (source == null) + throw Error.ArgumentNull("source"); + if (predicate == null) + throw Error.ArgumentNull("predicate"); + return source.Provider.Execute( + Expression.Call( + null, + GetMethodInfoOf(() => Queryable.Single(source, predicate)), + new Expression[] { source.Expression, Expression.Quote(predicate) } + )); + } + + public static TSource SingleOrDefault(this IQueryable source) + { + if (source == null) + throw Error.ArgumentNull("source"); + return source.Provider.Execute( + Expression.Call( + null, + GetMethodInfoOf(() => Queryable.SingleOrDefault(source)), + new Expression[] { source.Expression } + )); + } + + public static TSource SingleOrDefault(this IQueryable source, Expression> predicate) + { + if (source == null) + throw Error.ArgumentNull("source"); + if (predicate == null) + throw Error.ArgumentNull("predicate"); + return source.Provider.Execute( + Expression.Call( + null, + GetMethodInfoOf(() => Queryable.SingleOrDefault(source, predicate)), + new Expression[] { source.Expression, Expression.Quote(predicate) } + )); + } + + public static TSource ElementAt(this IQueryable source, int index) + { + if (source == null) + throw Error.ArgumentNull("source"); + if (index < 0) + throw Error.ArgumentOutOfRange("index"); + return source.Provider.Execute( + Expression.Call( + null, + GetMethodInfoOf(() => Queryable.ElementAt(source, index)), + new Expression[] { source.Expression, Expression.Constant(index) } + )); + } + + public static TSource ElementAtOrDefault(this IQueryable source, int index) + { + if (source == null) + throw Error.ArgumentNull("source"); + return source.Provider.Execute( + Expression.Call( + null, + GetMethodInfoOf(() => Queryable.ElementAtOrDefault(source, index)), + new Expression[] { source.Expression, Expression.Constant(index) } + )); + } + + public static IQueryable DefaultIfEmpty(this IQueryable source) + { + if (source == null) + throw Error.ArgumentNull("source"); + return source.Provider.CreateQuery( + Expression.Call( + null, + GetMethodInfoOf(() => Queryable.DefaultIfEmpty(source)), + new Expression[] { source.Expression } + )); + } + + public static IQueryable DefaultIfEmpty(this IQueryable source, TSource defaultValue) + { + if (source == null) + throw Error.ArgumentNull("source"); + return source.Provider.CreateQuery( + Expression.Call( + null, + GetMethodInfoOf(() => Queryable.DefaultIfEmpty(source, defaultValue)), + new Expression[] { source.Expression, Expression.Constant(defaultValue, typeof(TSource)) } + )); + } + + public static bool Contains(this IQueryable source, TSource item) + { + if (source == null) + throw Error.ArgumentNull("source"); + return source.Provider.Execute( + Expression.Call( + null, + GetMethodInfoOf(() => Queryable.Contains(source, item)), + new Expression[] { source.Expression, Expression.Constant(item, typeof(TSource)) } + )); + } + + public static bool Contains(this IQueryable source, TSource item, IEqualityComparer comparer) + { + if (source == null) + throw Error.ArgumentNull("source"); + return source.Provider.Execute( + Expression.Call( + null, + GetMethodInfoOf(() => Queryable.Contains(source, item, comparer)), + new Expression[] { source.Expression, Expression.Constant(item, typeof(TSource)), Expression.Constant(comparer, typeof(IEqualityComparer)) } + )); + } + + public static IQueryable Reverse(this IQueryable source) + { + if (source == null) + throw Error.ArgumentNull("source"); + return source.Provider.CreateQuery( + Expression.Call( + null, + GetMethodInfoOf(() => Queryable.Reverse(source)), + new Expression[] { source.Expression } + )); + } + + public static bool SequenceEqual(this IQueryable source1, IEnumerable source2) + { + if (source1 == null) + throw Error.ArgumentNull("source1"); + if (source2 == null) + throw Error.ArgumentNull("source2"); + return source1.Provider.Execute( + Expression.Call( + null, + GetMethodInfoOf(() => Queryable.SequenceEqual(source1, source2)), + new Expression[] { source1.Expression, GetSourceExpression(source2) } + )); + } + + public static bool SequenceEqual(this IQueryable source1, IEnumerable source2, IEqualityComparer comparer) + { + if (source1 == null) + throw Error.ArgumentNull("source1"); + if (source2 == null) + throw Error.ArgumentNull("source2"); + return source1.Provider.Execute( + Expression.Call( + null, + GetMethodInfoOf(() => Queryable.SequenceEqual(source1, source2, comparer)), + new Expression[] { + source1.Expression, + GetSourceExpression(source2), + Expression.Constant(comparer, typeof(IEqualityComparer)) + } + )); + } + + public static bool Any(this IQueryable source) + { + if (source == null) + throw Error.ArgumentNull("source"); + return source.Provider.Execute( + Expression.Call( + null, + GetMethodInfoOf(() => Queryable.Any(source)), + new Expression[] { source.Expression } + )); + } + + public static bool Any(this IQueryable source, Expression> predicate) + { + if (source == null) + throw Error.ArgumentNull("source"); + if (predicate == null) + throw Error.ArgumentNull("predicate"); + return source.Provider.Execute( + Expression.Call( + null, + GetMethodInfoOf(() => Queryable.Any(source, predicate)), + new Expression[] { source.Expression, Expression.Quote(predicate) } + )); + } + + public static bool All(this IQueryable source, Expression> predicate) + { + if (source == null) + throw Error.ArgumentNull("source"); + if (predicate == null) + throw Error.ArgumentNull("predicate"); + return source.Provider.Execute( + Expression.Call( + null, + GetMethodInfoOf(() => Queryable.All(source, predicate)), + new Expression[] { source.Expression, Expression.Quote(predicate) } + )); + } + + public static int Count(this IQueryable source) + { + if (source == null) + throw Error.ArgumentNull("source"); + return source.Provider.Execute( + Expression.Call( + null, + GetMethodInfoOf(() => Queryable.Count(source)), + new Expression[] { source.Expression } + )); + } + + public static int Count(this IQueryable source, Expression> predicate) + { + if (source == null) + throw Error.ArgumentNull("source"); + if (predicate == null) + throw Error.ArgumentNull("predicate"); + return source.Provider.Execute( + Expression.Call( + null, + GetMethodInfoOf(() => Queryable.Count(source, predicate)), + new Expression[] { source.Expression, Expression.Quote(predicate) } + )); + } + + public static long LongCount(this IQueryable source) + { + if (source == null) + throw Error.ArgumentNull("source"); + return source.Provider.Execute( + Expression.Call( + null, + GetMethodInfoOf(() => Queryable.LongCount(source)), + new Expression[] { source.Expression } + )); + } + + public static long LongCount(this IQueryable source, Expression> predicate) + { + if (source == null) + throw Error.ArgumentNull("source"); + if (predicate == null) + throw Error.ArgumentNull("predicate"); + return source.Provider.Execute( + Expression.Call( + null, + GetMethodInfoOf(() => Queryable.LongCount(source, predicate)), + new Expression[] { source.Expression, Expression.Quote(predicate) } + )); + } + + public static TSource Min(this IQueryable source) + { + if (source == null) + throw Error.ArgumentNull("source"); + return source.Provider.Execute( + Expression.Call( + null, + GetMethodInfoOf(() => Queryable.Min(source)), + new Expression[] { source.Expression } + )); + } + + public static TResult Min(this IQueryable source, Expression> selector) + { + if (source == null) + throw Error.ArgumentNull("source"); + if (selector == null) + throw Error.ArgumentNull("selector"); + return source.Provider.Execute( + Expression.Call( + null, + GetMethodInfoOf(() => Queryable.Min(source, selector)), + new Expression[] { source.Expression, Expression.Quote(selector) } + )); + } + + public static TSource Max(this IQueryable source) + { + if (source == null) + throw Error.ArgumentNull("source"); + return source.Provider.Execute( + Expression.Call( + null, + GetMethodInfoOf(() => Queryable.Max(source)), + new Expression[] { source.Expression } + )); + } + + public static TResult Max(this IQueryable source, Expression> selector) + { + if (source == null) + throw Error.ArgumentNull("source"); + if (selector == null) + throw Error.ArgumentNull("selector"); + return source.Provider.Execute( + Expression.Call( + null, + GetMethodInfoOf(() => Queryable.Max(source, selector)), + new Expression[] { source.Expression, Expression.Quote(selector) } + )); + } + + public static int Sum(this IQueryable source) + { + if (source == null) + throw Error.ArgumentNull("source"); + return source.Provider.Execute( + Expression.Call( + null, + GetMethodInfoOf(() => Queryable.Sum(source)), + new Expression[] { source.Expression } + )); + } + + public static int? Sum(this IQueryable source) + { + if (source == null) + throw Error.ArgumentNull("source"); + return source.Provider.Execute( + Expression.Call( + null, + GetMethodInfoOf(() => Queryable.Sum(source)), + new Expression[] { source.Expression } + )); + } + + public static long Sum(this IQueryable source) + { + if (source == null) + throw Error.ArgumentNull("source"); + return source.Provider.Execute( + Expression.Call( + null, + GetMethodInfoOf(() => Queryable.Sum(source)), + new Expression[] { source.Expression } + )); + } + + public static long? Sum(this IQueryable source) + { + if (source == null) + throw Error.ArgumentNull("source"); + return source.Provider.Execute( + Expression.Call( + null, + GetMethodInfoOf(() => Queryable.Sum(source)), + new Expression[] { source.Expression } + )); + } + + public static float Sum(this IQueryable source) + { + if (source == null) + throw Error.ArgumentNull("source"); + return source.Provider.Execute( + Expression.Call( + null, + GetMethodInfoOf(() => Queryable.Sum(source)), + new Expression[] { source.Expression } + )); + } + + public static float? Sum(this IQueryable source) + { + if (source == null) + throw Error.ArgumentNull("source"); + return source.Provider.Execute( + Expression.Call( + null, + GetMethodInfoOf(() => Queryable.Sum(source)), + new Expression[] { source.Expression } + )); + } + + public static double Sum(this IQueryable source) + { + if (source == null) + throw Error.ArgumentNull("source"); + return source.Provider.Execute( + Expression.Call( + null, + GetMethodInfoOf(() => Queryable.Sum(source)), + new Expression[] { source.Expression } + )); + } + + public static double? Sum(this IQueryable source) + { + if (source == null) + throw Error.ArgumentNull("source"); + return source.Provider.Execute( + Expression.Call( + null, + GetMethodInfoOf(() => Queryable.Sum(source)), + new Expression[] { source.Expression } + )); + } + + public static decimal Sum(this IQueryable source) + { + if (source == null) + throw Error.ArgumentNull("source"); + return source.Provider.Execute( + Expression.Call( + null, + GetMethodInfoOf(() => Queryable.Sum(source)), + new Expression[] { source.Expression } + )); + } + + public static decimal? Sum(this IQueryable source) + { + if (source == null) + throw Error.ArgumentNull("source"); + return source.Provider.Execute( + Expression.Call( + null, + GetMethodInfoOf(() => Queryable.Sum(source)), + new Expression[] { source.Expression } + )); + } + + public static int Sum(this IQueryable source, Expression> selector) + { + if (source == null) + throw Error.ArgumentNull("source"); + if (selector == null) + throw Error.ArgumentNull("selector"); + return source.Provider.Execute( + Expression.Call( + null, + GetMethodInfoOf(() => Queryable.Sum(source, selector)), + new Expression[] { source.Expression, Expression.Quote(selector) } + )); + } + + public static int? Sum(this IQueryable source, Expression> selector) + { + if (source == null) + throw Error.ArgumentNull("source"); + if (selector == null) + throw Error.ArgumentNull("selector"); + return source.Provider.Execute( + Expression.Call( + null, + GetMethodInfoOf(() => Queryable.Sum(source, selector)), + new Expression[] { source.Expression, Expression.Quote(selector) } + )); + } + + public static long Sum(this IQueryable source, Expression> selector) + { + if (source == null) + throw Error.ArgumentNull("source"); + if (selector == null) + throw Error.ArgumentNull("selector"); + return source.Provider.Execute( + Expression.Call( + null, + GetMethodInfoOf(() => Queryable.Sum(source, selector)), + new Expression[] { source.Expression, Expression.Quote(selector) } + )); + } + + public static long? Sum(this IQueryable source, Expression> selector) + { + if (source == null) + throw Error.ArgumentNull("source"); + if (selector == null) + throw Error.ArgumentNull("selector"); + return source.Provider.Execute( + Expression.Call( + null, + GetMethodInfoOf(() => Queryable.Sum(source, selector)), + new Expression[] { source.Expression, Expression.Quote(selector) } + )); + } + + public static float Sum(this IQueryable source, Expression> selector) + { + if (source == null) + throw Error.ArgumentNull("source"); + if (selector == null) + throw Error.ArgumentNull("selector"); + return source.Provider.Execute( + Expression.Call( + null, + GetMethodInfoOf(() => Queryable.Sum(source, selector)), + new Expression[] { source.Expression, Expression.Quote(selector) } + )); + } + + public static float? Sum(this IQueryable source, Expression> selector) + { + if (source == null) + throw Error.ArgumentNull("source"); + if (selector == null) + throw Error.ArgumentNull("selector"); + return source.Provider.Execute( + Expression.Call( + null, + GetMethodInfoOf(() => Queryable.Sum(source, selector)), + new Expression[] { source.Expression, Expression.Quote(selector) } + )); + } + + public static double Sum(this IQueryable source, Expression> selector) + { + if (source == null) + throw Error.ArgumentNull("source"); + if (selector == null) + throw Error.ArgumentNull("selector"); + return source.Provider.Execute( + Expression.Call( + null, + GetMethodInfoOf(() => Queryable.Sum(source, selector)), + new Expression[] { source.Expression, Expression.Quote(selector) } + )); + } + + public static double? Sum(this IQueryable source, Expression> selector) + { + if (source == null) + throw Error.ArgumentNull("source"); + if (selector == null) + throw Error.ArgumentNull("selector"); + return source.Provider.Execute( + Expression.Call( + null, + GetMethodInfoOf(() => Queryable.Sum(source, selector)), + new Expression[] { source.Expression, Expression.Quote(selector) } + )); + } + + public static decimal Sum(this IQueryable source, Expression> selector) + { + if (source == null) + throw Error.ArgumentNull("source"); + if (selector == null) + throw Error.ArgumentNull("selector"); + return source.Provider.Execute( + Expression.Call( + null, + GetMethodInfoOf(() => Queryable.Sum(source, selector)), + new Expression[] { source.Expression, Expression.Quote(selector) } + )); + } + + public static decimal? Sum(this IQueryable source, Expression> selector) + { + if (source == null) + throw Error.ArgumentNull("source"); + if (selector == null) + throw Error.ArgumentNull("selector"); + return source.Provider.Execute( + Expression.Call( + null, + GetMethodInfoOf(() => Queryable.Sum(source, selector)), + new Expression[] { source.Expression, Expression.Quote(selector) } + )); + } + + public static double Average(this IQueryable source) + { + if (source == null) + throw Error.ArgumentNull("source"); + return source.Provider.Execute( + Expression.Call( + null, + GetMethodInfoOf(() => Queryable.Average(source)), + new Expression[] { source.Expression } + )); + } + + public static double? Average(this IQueryable source) + { + if (source == null) + throw Error.ArgumentNull("source"); + return source.Provider.Execute( + Expression.Call( + null, + GetMethodInfoOf(() => Queryable.Average(source)), + new Expression[] { source.Expression } + )); + } + + public static double Average(this IQueryable source) + { + if (source == null) + throw Error.ArgumentNull("source"); + return source.Provider.Execute( + Expression.Call( + null, + GetMethodInfoOf(() => Queryable.Average(source)), + new Expression[] { source.Expression } + )); + } + + public static double? Average(this IQueryable source) + { + if (source == null) + throw Error.ArgumentNull("source"); + return source.Provider.Execute( + Expression.Call( + null, + GetMethodInfoOf(() => Queryable.Average(source)), + new Expression[] { source.Expression } + )); + } + + public static float Average(this IQueryable source) + { + if (source == null) + throw Error.ArgumentNull("source"); + return source.Provider.Execute( + Expression.Call( + null, + GetMethodInfoOf(() => Queryable.Average(source)), + new Expression[] { source.Expression } + )); + } + + public static float? Average(this IQueryable source) + { + if (source == null) + throw Error.ArgumentNull("source"); + return source.Provider.Execute( + Expression.Call( + null, + GetMethodInfoOf(() => Queryable.Average(source)), + new Expression[] { source.Expression } + )); + } + + public static double Average(this IQueryable source) + { + if (source == null) + throw Error.ArgumentNull("source"); + return source.Provider.Execute( + Expression.Call( + null, + GetMethodInfoOf(() => Queryable.Average(source)), + new Expression[] { source.Expression } + )); + } + + public static double? Average(this IQueryable source) + { + if (source == null) + throw Error.ArgumentNull("source"); + return source.Provider.Execute( + Expression.Call( + null, + GetMethodInfoOf(() => Queryable.Average(source)), + new Expression[] { source.Expression } + )); + } + + public static decimal Average(this IQueryable source) + { + if (source == null) + throw Error.ArgumentNull("source"); + return source.Provider.Execute( + Expression.Call( + null, + GetMethodInfoOf(() => Queryable.Average(source)), + new Expression[] { source.Expression } + )); + } + + public static decimal? Average(this IQueryable source) + { + if (source == null) + throw Error.ArgumentNull("source"); + return source.Provider.Execute( + Expression.Call( + null, + GetMethodInfoOf(() => Queryable.Average(source)), + new Expression[] { source.Expression } + )); + } + + public static double Average(this IQueryable source, Expression> selector) + { + if (source == null) + throw Error.ArgumentNull("source"); + if (selector == null) + throw Error.ArgumentNull("selector"); + return source.Provider.Execute( + Expression.Call( + null, + GetMethodInfoOf(() => Queryable.Average(source, selector)), + new Expression[] { source.Expression, Expression.Quote(selector) } + )); + } + + public static double? Average(this IQueryable source, Expression> selector) + { + if (source == null) + throw Error.ArgumentNull("source"); + if (selector == null) + throw Error.ArgumentNull("selector"); + return source.Provider.Execute( + Expression.Call( + null, + GetMethodInfoOf(() => Queryable.Average(source, selector)), + new Expression[] { source.Expression, Expression.Quote(selector) } + )); + } + + public static float Average(this IQueryable source, Expression> selector) + { + if (source == null) + throw Error.ArgumentNull("source"); + if (selector == null) + throw Error.ArgumentNull("selector"); + return source.Provider.Execute( + Expression.Call( + null, + GetMethodInfoOf(() => Queryable.Average(source, selector)), + new Expression[] { source.Expression, Expression.Quote(selector) } + )); + } + + public static float? Average(this IQueryable source, Expression> selector) + { + if (source == null) + throw Error.ArgumentNull("source"); + if (selector == null) + throw Error.ArgumentNull("selector"); + return source.Provider.Execute( + Expression.Call( + null, + GetMethodInfoOf(() => Queryable.Average(source, selector)), + new Expression[] { source.Expression, Expression.Quote(selector) } + )); + } + + public static double Average(this IQueryable source, Expression> selector) + { + if (source == null) + throw Error.ArgumentNull("source"); + if (selector == null) + throw Error.ArgumentNull("selector"); + return source.Provider.Execute( + Expression.Call( + null, + GetMethodInfoOf(() => Queryable.Average(source, selector)), + new Expression[] { source.Expression, Expression.Quote(selector) } + )); + } + + public static double? Average(this IQueryable source, Expression> selector) + { + if (source == null) + throw Error.ArgumentNull("source"); + if (selector == null) + throw Error.ArgumentNull("selector"); + return source.Provider.Execute( + Expression.Call( + null, + GetMethodInfoOf(() => Queryable.Average(source, selector)), + new Expression[] { source.Expression, Expression.Quote(selector) } + )); + } + + public static double Average(this IQueryable source, Expression> selector) + { + if (source == null) + throw Error.ArgumentNull("source"); + if (selector == null) + throw Error.ArgumentNull("selector"); + return source.Provider.Execute( + Expression.Call( + null, + GetMethodInfoOf(() => Queryable.Average(source, selector)), + new Expression[] { source.Expression, Expression.Quote(selector) } + )); + } + + public static double? Average(this IQueryable source, Expression> selector) + { + if (source == null) + throw Error.ArgumentNull("source"); + if (selector == null) + throw Error.ArgumentNull("selector"); + return source.Provider.Execute( + Expression.Call( + null, + GetMethodInfoOf(() => Queryable.Average(source, selector)), + new Expression[] { source.Expression, Expression.Quote(selector) } + )); + } + + public static decimal Average(this IQueryable source, Expression> selector) + { + if (source == null) + throw Error.ArgumentNull("source"); + if (selector == null) + throw Error.ArgumentNull("selector"); + return source.Provider.Execute( + Expression.Call( + null, + GetMethodInfoOf(() => Queryable.Average(source, selector)), + new Expression[] { source.Expression, Expression.Quote(selector) } + )); + } + + public static decimal? Average(this IQueryable source, Expression> selector) + { + if (source == null) + throw Error.ArgumentNull("source"); + if (selector == null) + throw Error.ArgumentNull("selector"); + return source.Provider.Execute( + Expression.Call( + null, + GetMethodInfoOf(() => Queryable.Average(source, selector)), + new Expression[] { source.Expression, Expression.Quote(selector) } + )); + } + + public static TSource Aggregate(this IQueryable source, Expression> func) + { + if (source == null) + throw Error.ArgumentNull("source"); + if (func == null) + throw Error.ArgumentNull("func"); + return source.Provider.Execute( + Expression.Call( + null, + GetMethodInfoOf(() => Queryable.Aggregate(source, func)), + new Expression[] { source.Expression, Expression.Quote(func) } + )); + } + + public static TAccumulate Aggregate(this IQueryable source, TAccumulate seed, Expression> func) + { + if (source == null) + throw Error.ArgumentNull("source"); + if (func == null) + throw Error.ArgumentNull("func"); + return source.Provider.Execute( + Expression.Call( + null, + GetMethodInfoOf(() => Queryable.Aggregate(source, seed, func)), + new Expression[] { source.Expression, Expression.Constant(seed), Expression.Quote(func) } + )); + } + + public static TResult Aggregate(this IQueryable source, TAccumulate seed, Expression> func, Expression> selector) + { + if (source == null) + throw Error.ArgumentNull("source"); + if (func == null) + throw Error.ArgumentNull("func"); + if (selector == null) + throw Error.ArgumentNull("selector"); + return source.Provider.Execute( + Expression.Call( + null, + GetMethodInfoOf(() => Queryable.Aggregate(source, seed, func, selector)), + new Expression[] { source.Expression, Expression.Constant(seed), Expression.Quote(func), Expression.Quote(selector) } + )); + } + + private static MethodInfo GetMethodInfoOf(Expression> expression) + { + var body = (MethodCallExpression)expression.Body; + return body.Method; + } + } +} \ No newline at end of file diff --git a/src/System.Linq.Queryable/src/System/Linq/Strings.cs b/src/System.Linq.Queryable/src/System/Linq/Strings.cs new file mode 100644 index 000000000000..21710cd65f92 --- /dev/null +++ b/src/System.Linq.Queryable/src/System/Linq/Strings.cs @@ -0,0 +1,41 @@ +// Copyright (c) Microsoft. All rights reserved. +// Licensed under the MIT license. See LICENSE file in the project root for full license information. + +namespace System.Linq +{ + /// + /// Strongly-typed and parameterized string resources. + /// + internal static class Strings + { + internal static string ArgumentNotIEnumerableGeneric(string message) + { + return SR.Format(SR.ArgumentNotIEnumerableGeneric, message); + } + + internal static string ArgumentNotValid(string message) + { + return SR.Format(SR.ArgumentNotValid, message); + } + + internal static string UnhandledExpressionType(object message) + { + return SR.Format(SR.UnhandledExpressionType, message); + } + + internal static string UnhandledBindingType(object message) + { + return SR.Format(SR.UnhandledBindingType, message); + } + + internal static string NoMethodOnType(string name, object type) + { + return SR.Format(SR.NoMethodOnType, name, type); + } + + internal static string NoMethodOnTypeMatchingArguments(string name, object type) + { + return SR.Format(SR.NoMethodOnTypeMatchingArguments, name, type); + } + } +} diff --git a/src/System.Linq.Queryable/src/System/Linq/TypeHelper.cs b/src/System.Linq.Queryable/src/System/Linq/TypeHelper.cs new file mode 100644 index 000000000000..2f43999b785d --- /dev/null +++ b/src/System.Linq.Queryable/src/System/Linq/TypeHelper.cs @@ -0,0 +1,57 @@ +// Copyright (c) Microsoft. All rights reserved. +// Licensed under the MIT license. See LICENSE file in the project root for full license information. + +using System; +using System.Collections.Generic; +using System.Text; +using System.Reflection; +using System.Linq.Expressions; + +namespace System.Linq +{ + internal static class TypeHelper + { + internal static Type FindGenericType(Type definition, Type type) + { + while (type != null && type != typeof(object)) + { + if (type.GetTypeInfo().IsGenericType && type.GetTypeInfo().GetGenericTypeDefinition() == definition) + return type; + if (definition.GetTypeInfo().IsInterface) + { + foreach (Type itype in type.GetTypeInfo().ImplementedInterfaces) + { + Type found = FindGenericType(definition, itype); + if (found != null) + return found; + } + } + type = type.GetTypeInfo().BaseType; + } + return null; + } + + internal static bool IsAssignableFrom(this Type source, Type destination) + { + return source.GetTypeInfo().IsAssignableFrom(destination.GetTypeInfo()); + } + + internal static Type[] GetGenericArguments(this Type type) + { + return type.GetTypeInfo().GenericTypeArguments; + } + + internal static MethodInfo[] GetStaticMethods(this Type type) + { + var list = new List(); + foreach (var method in type.GetRuntimeMethods()) + { + if (method.IsStatic) + { + list.Add(method); + } + } + return list.ToArray(); + } + } +} diff --git a/src/System.Linq.Queryable/src/packages.config b/src/System.Linq.Queryable/src/packages.config new file mode 100644 index 000000000000..6e5759b59f46 --- /dev/null +++ b/src/System.Linq.Queryable/src/packages.config @@ -0,0 +1,15 @@ + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/src/System.Linq.Queryable/tests/Queryable.cs b/src/System.Linq.Queryable/tests/Queryable.cs new file mode 100644 index 000000000000..8704fe914f22 --- /dev/null +++ b/src/System.Linq.Queryable/tests/Queryable.cs @@ -0,0 +1,875 @@ +// Copyright (c) Microsoft. All rights reserved. +// Licensed under the MIT license. See LICENSE file in the project root for full license information. + +using System; +using System.Collections; +using System.Collections.Generic; +using System.Linq; +using Xunit; + +namespace System.Linq.Tests +{ + public class QueryableTests + { + [Fact] + public void AsQueryable() + { + var x = ((IEnumerable)(new int[] { })).AsQueryable(); + } + + [Fact] + public void AsQueryableT() + { + var x = (new int[] { }).AsQueryable(); + } + + [Fact] + public void Count1() + { + var count = (new int[] { 0 }).AsQueryable().Count(); + Assert.Equal(1, count); + } + + [Fact] + public void Count2() + { + var count = (new int[] { 0, 1, 2 }).AsQueryable().Count(n => n > 0); + Assert.Equal(2, count); + } + + [Fact] + public void Where1() + { + var count = (new int[] { 0, 1, 2 }).AsQueryable().Where(n => n > 1).Count(); + Assert.Equal(1, count); + } + + [Fact] + public void Where2() + { + var count = (new int[] { 0, 1, 2 }).AsQueryable().Where((n, i) => n > 1 || i == 0).Count(); + Assert.Equal(2, count); + } + + [Fact] + public void OfType() + { + var count = (new object[] { 0, (long)1, 2 }).AsQueryable().OfType().Count(); + Assert.Equal(2, count); + } + + [Fact] + public void Cast() + { + var count = (new object[] { 0, 1, 2 }).AsQueryable().Cast().Count(); + Assert.Equal(3, count); + } + + [Fact] + public void Select1() + { + var count = (new object[] { 0, 1, 2 }).AsQueryable().Select(o => (int)o).Count(); + Assert.Equal(3, count); + } + + [Fact] + public void Select2() + { + var count = (new object[] { 0, 1, 2 }).AsQueryable().Select((o, i) => (int)o + i).Count(); + Assert.Equal(3, count); + } + + [Fact] + public void SelectMany1() + { + var count = (new int[] { 0, 1, 2 }).AsQueryable().SelectMany(n => new int[] { n + 4, 5 }).Count(); + Assert.Equal(6, count); + } + + [Fact] + public void SelectMany2() + { + var count = (new int[] { 0, 1, 2 }).AsQueryable().SelectMany((n, i) => new int[] { 4 + i, 5 + n }).Count(); + Assert.Equal(6, count); + } + + [Fact] + public void SelectMany3() + { + var count = (new int[] { 0, 1, 2 }).AsQueryable().SelectMany(n => new long[] { n + 4, 5 }, (n1, n2) => (n1 + n2).ToString()).Count(); + Assert.Equal(6, count); + } + + [Fact] + public void SelectMany4() + { + var count = (new int[] { 0, 1, 2 }).AsQueryable().SelectMany((n, i) => new long[] { 4 + i, 5 + n }, (n1, n2) => (n1 + n2).ToString()).Count(); + Assert.Equal(6, count); + } + + [Fact] + public void Join1() + { + var count = (new int[] { 0, 1, 2 }).AsQueryable().Join(new int[] { 1, 2, 3 }, n1 => n1, n2 => n2, (n1, n2) => n1 + n2).Count(); + Assert.Equal(2, count); + } + + [Fact] + public void Join2() + { + var count = (new int[] { 0, 1, 2 }).AsQueryable().Join(new int[] { 1, 2, 3 }, n1 => n1, n2 => n2, (n1, n2) => n1 + n2, EqualityComparer.Default).Count(); + Assert.Equal(2, count); + } + + [Fact] + public void GroupJoin1() + { + var count = (new int[] { 0, 1, 2 }).AsQueryable().GroupJoin(new int[] { 1, 2, 3 }, n1 => n1, n2 => n2, (n1, n2) => n1).Count(); + Assert.Equal(3, count); + } + + [Fact] + public void GroupJoin2() + { + var count = (new int[] { 0, 1, 2 }).AsQueryable().GroupJoin(new int[] { 1, 2, 3 }, n1 => n1, n2 => n2, (n1, n2) => n1, EqualityComparer.Default).Count(); + Assert.Equal(3, count); + } + + [Fact] + public void OrderBy1() + { + var count = (new int[] { 0, 1, 2 }).AsQueryable().OrderBy(n => n).Count(); + Assert.Equal(3, count); + } + + [Fact] + public void OrderBy2() + { + var count = (new int[] { 0, 1, 2 }).AsQueryable().OrderBy(n => n, Comparer.Default).Count(); + Assert.Equal(3, count); + } + + [Fact] + public void OrderByDescending1() + { + var count = (new int[] { 0, 1, 2 }).AsQueryable().OrderByDescending(n => n).Count(); + Assert.Equal(3, count); + } + + [Fact] + public void OrderByDescending2() + { + var count = (new int[] { 0, 1, 2 }).AsQueryable().OrderByDescending(n => n, Comparer.Default).Count(); + Assert.Equal(3, count); + } + + [Fact] + public void ThenBy1() + { + var count = (new int[] { 0, 1, 2 }).AsQueryable().OrderBy(n => n).ThenBy(n => n).Count(); + Assert.Equal(3, count); + } + + [Fact] + public void ThenBy2() + { + var count = (new int[] { 0, 1, 2 }).AsQueryable().OrderBy(n => n).ThenBy(n => n, Comparer.Default).Count(); + Assert.Equal(3, count); + } + + [Fact] + public void ThenByDescending1() + { + var count = (new int[] { 0, 1, 2 }).AsQueryable().OrderBy(n => n).ThenByDescending(n => n).Count(); + Assert.Equal(3, count); + } + + [Fact] + public void ThenByDescending2() + { + var count = (new int[] { 0, 1, 2 }).AsQueryable().OrderBy(n => n).ThenByDescending(n => n, Comparer.Default).Count(); + Assert.Equal(3, count); + } + + [Fact] + public void Take() + { + var count = (new int[] { 0, 1, 2 }).AsQueryable().Take(2).Count(); + Assert.Equal(2, count); + } + + [Fact] + public void TakeWhile1() + { + var count = (new int[] { 0, 1, 2 }).AsQueryable().TakeWhile(n => n < 2).Count(); + Assert.Equal(2, count); + } + + [Fact] + public void TakeWhile2() + { + var count = (new int[] { 0, 1, 2 }).AsQueryable().TakeWhile((n, i) => n + i < 4).Count(); + Assert.Equal(2, count); + } + + [Fact] + public void Skip() + { + var count = (new int[] { 0, 1, 2 }).AsQueryable().Skip(1).Count(); + Assert.Equal(2, count); + } + + [Fact] + public void SkipWhile1() + { + var count = (new int[] { 0, 1, 2 }).AsQueryable().SkipWhile(n => n < 1).Count(); + Assert.Equal(2, count); + } + + [Fact] + public void SkipWhile2() + { + var count = (new int[] { 0, 1, 2 }).AsQueryable().SkipWhile((n, i) => n + i < 1).Count(); + Assert.Equal(2, count); + } + + [Fact] + public void GroupBy1() + { + var count = (new int[] { 0, 1, 2, 2, 0 }).AsQueryable().GroupBy(n => n).Count(); + Assert.Equal(3, count); + } + + [Fact] + public void GroupBy2() + { + var count = (new int[] { 0, 1, 2, 2, 0 }).AsQueryable().GroupBy(n => n, EqualityComparer.Default).Count(); + Assert.Equal(3, count); + } + + [Fact] + public void GroupBy3() + { + var count = (new int[] { 0, 1, 2, 2, 0 }).AsQueryable().GroupBy(n => n, n => n).Count(); + Assert.Equal(3, count); + } + + [Fact] + public void GroupBy4() + { + var count = (new int[] { 0, 1, 2, 2, 0 }).AsQueryable().GroupBy(n => n, n => n, EqualityComparer.Default).Count(); + Assert.Equal(3, count); + } + + [Fact] + public void GroupBy5() + { + var count = (new int[] { 0, 1, 2, 2, 0 }).AsQueryable().GroupBy(n => n, n => n, (k, g) => k).Count(); + Assert.Equal(3, count); + } + + [Fact] + public void GroupBy6() + { + var count = (new int[] { 0, 1, 2, 2, 0 }).AsQueryable().GroupBy(n => n, (k, g) => k).Count(); + Assert.Equal(3, count); + } + + [Fact] + public void GroupBy7() + { + var count = (new int[] { 0, 1, 2, 2, 0 }).AsQueryable().GroupBy(n => n, n => n, (k, g) => k, EqualityComparer.Default).Count(); + Assert.Equal(3, count); + } + + [Fact] + public void GroupBy8() + { + var count = (new int[] { 0, 1, 2, 2, 0 }).AsQueryable().GroupBy(n => n, (k, g) => k, EqualityComparer.Default).Count(); + Assert.Equal(3, count); + } + + [Fact] + public void Distinct1() + { + var count = (new int[] { 0, 1, 2, 2, 0 }).AsQueryable().Distinct().Count(); + Assert.Equal(3, count); + } + + [Fact] + public void Distinct2() + { + var count = (new int[] { 0, 1, 2, 2, 0 }).AsQueryable().Distinct(EqualityComparer.Default).Count(); + Assert.Equal(3, count); + } + + [Fact] + public void Concat() + { + var count = (new int[] { 0, 1, 2 }).AsQueryable().Concat((new int[] { 10, 11, 12 }).AsQueryable()).Count(); + Assert.Equal(6, count); + } + + [Fact] + public void Zip() + { + var count = (new int[] { 0, 1, 2 }).AsQueryable().Zip((new int[] { 10, 11, 12 }).AsQueryable(), (n1, n2) => n1 + n2).Count(); + Assert.Equal(3, count); + } + + [Fact] + public void Union1() + { + var count = (new int[] { 0, 1, 2 }).AsQueryable().Union((new int[] { 1, 2, 3 }).AsQueryable()).Count(); + Assert.Equal(4, count); + } + + [Fact] + public void Union2() + { + var count = (new int[] { 0, 1, 2 }).AsQueryable().Union((new int[] { 1, 2, 3 }).AsQueryable(), EqualityComparer.Default).Count(); + Assert.Equal(4, count); + } + + [Fact] + public void Intersect1() + { + var count = (new int[] { 0, 1, 2 }).AsQueryable().Intersect((new int[] { 1, 2, 3 }).AsQueryable()).Count(); + Assert.Equal(2, count); + } + + [Fact] + public void Intersect2() + { + var count = (new int[] { 0, 1, 2 }).AsQueryable().Intersect((new int[] { 1, 2, 3 }).AsQueryable(), EqualityComparer.Default).Count(); + Assert.Equal(2, count); + } + + [Fact] + public void Except1() + { + var count = (new int[] { 0, 1, 2 }).AsQueryable().Except((new int[] { 1, 2, 3 }).AsQueryable()).Count(); + Assert.Equal(1, count); + } + + [Fact] + public void Except2() + { + var count = (new int[] { 0, 1, 2 }).AsQueryable().Except((new int[] { 1, 2, 3 }).AsQueryable(), EqualityComparer.Default).Count(); + Assert.Equal(1, count); + } + + [Fact] + public void First1() + { + var val = (new int[] { 1, 2 }).AsQueryable().First(); + Assert.Equal(1, val); + } + + [Fact] + public void First2() + { + var val = (new int[] { 0, 1, 2 }).AsQueryable().First(n => n > 1); + Assert.Equal(2, val); + } + + [Fact] + public void FirstOrDefault1() + { + var val = (new int[] { 1, 2 }).AsQueryable().FirstOrDefault(); + Assert.Equal(1, val); + } + + [Fact] + public void FirstOrDefault2() + { + var val = (new int[] { 0, 1, 2 }).AsQueryable().FirstOrDefault(n => n > 1); + Assert.Equal(2, val); + } + + [Fact] + public void Last1() + { + var val = (new int[] { 0, 1, 2 }).AsQueryable().Last(); + Assert.Equal(2, val); + } + + [Fact] + public void Last2() + { + var val = (new int[] { 0, 1, 2 }).AsQueryable().Last(n => n > 1); + Assert.Equal(2, val); + } + + [Fact] + public void LastOrDefault1() + { + var val = (new int[] { 0, 1, 2 }).AsQueryable().LastOrDefault(); + Assert.Equal(2, val); + } + + [Fact] + public void LastOrDefault2() + { + var val = (new int[] { 0, 1, 2 }).AsQueryable().LastOrDefault(n => n > 1); + Assert.Equal(2, val); + } + + [Fact] + public void Single1() + { + var val = (new int[] { 2 }).AsQueryable().Single(); + Assert.Equal(2, val); + } + + [Fact] + public void Single2() + { + var val = (new int[] { 2 }).AsQueryable().Single(n => n > 1); + Assert.Equal(2, val); + } + + [Fact] + public void SingleOrDefault1() + { + var val = (new int[] { 2 }).AsQueryable().SingleOrDefault(); + Assert.Equal(2, val); + } + + [Fact] + public void SingleOrDefault2() + { + var val = (new int[] { 2 }).AsQueryable().SingleOrDefault(n => n > 1); + Assert.Equal(2, val); + } + + [Fact] + public void ElementAt() + { + var val = (new int[] { 0, 2, 1 }).AsQueryable().ElementAt(1); + Assert.Equal(2, val); + } + + [Fact] + public void ElementAtOrDefault() + { + var val = (new int[] { 0, 2, 1 }).AsQueryable().ElementAtOrDefault(1); + Assert.Equal(2, val); + } + + [Fact] + public void DefaultIfEmpty1() + { + var count = (new int[] { }).AsQueryable().DefaultIfEmpty().Count(); + Assert.Equal(1, count); + } + + [Fact] + public void DefaultIfEmpty2() + { + var count = (new int[] { }).AsQueryable().DefaultIfEmpty(3).Count(); + Assert.Equal(1, count); + } + + [Fact] + public void Contains1() + { + var val = (new int[] { 0, 2, 1 }).AsQueryable().Contains(1); + Assert.True(val); + } + + [Fact] + public void Contains2() + { + var val = (new int[] { 0, 2, 1 }).AsQueryable().Contains(1, EqualityComparer.Default); + Assert.True(val); + } + + [Fact] + public void Reverse() + { + var count = (new int[] { 0, 2, 1 }).AsQueryable().Reverse().Count(); + Assert.Equal(3, count); + } + + [Fact] + public void SequenceEqual1() + { + var val = (new int[] { 0, 2, 1 }).AsQueryable().SequenceEqual(new int[] { 0, 2, 1 }); + Assert.True(val); + } + + [Fact] + public void SequenceEqual2() + { + var val = (new int[] { 0, 2, 1 }).AsQueryable().SequenceEqual(new int[] { 0, 2, 1 }, EqualityComparer.Default); + Assert.True(val); + } + + [Fact] + public void Any1() + { + var val = (new int[] { 0, 2, 1 }).AsQueryable().Any(); + Assert.True(val); + } + + [Fact] + public void Any2() + { + var val = (new int[] { 0, 2, 1 }).AsQueryable().Any(n => n > 1); + Assert.True(val); + } + + [Fact] + public void All() + { + var val = (new int[] { 0, 2, 1 }).AsQueryable().All(n => n > 1); + Assert.False(val); + } + + [Fact] + public void LongCount1() + { + var count = (new int[] { 0 }).AsQueryable().LongCount(); + Assert.Equal(1L, count); + } + + [Fact] + public void LongCount2() + { + var count = (new int[] { 0, 1, 2 }).AsQueryable().LongCount(n => n > 0); + Assert.Equal(2L, count); + } + + [Fact] + public void Min1() + { + var val = (new int[] { 0, 2, 1 }).AsQueryable().Min(); + Assert.Equal(0, val); + } + + [Fact] + public void Min2() + { + var val = (new int[] { 0, 2, 1 }).AsQueryable().Min(n => n); + Assert.Equal(0, val); + } + + [Fact] + public void Max1() + { + var val = (new int[] { 0, 2, 1 }).AsQueryable().Max(); + Assert.Equal(2, val); + } + + [Fact] + public void Max2() + { + var val = (new int[] { 0, 2, 1 }).AsQueryable().Max(n => n); + Assert.Equal(2, val); + } + + [Fact] + public void Sum1() + { + var val = (new int[] { 0, 2, 1 }).AsQueryable().Sum(); + Assert.Equal((int)3, val); + } + + [Fact] + public void Sum2() + { + var val = (new int?[] { 0, 2, 1 }).AsQueryable().Sum(); + Assert.Equal((int)3, val); + } + + [Fact] + public void Sum3() + { + var val = (new long[] { 0, 2, 1 }).AsQueryable().Sum(); + Assert.Equal((long)3, val); + } + + [Fact] + public void Sum4() + { + var val = (new long?[] { 0, 2, 1 }).AsQueryable().Sum(); + Assert.Equal((long)3, val); + } + + [Fact] + public void Sum5() + { + var val = (new float[] { 0, 2, 1 }).AsQueryable().Sum(); + Assert.Equal((float)3, val); + } + + [Fact] + public void Sum6() + { + var val = (new float?[] { 0, 2, 1 }).AsQueryable().Sum(); + Assert.Equal((float)3, val); + } + + [Fact] + public void Sum7() + { + var val = (new double[] { 0, 2, 1 }).AsQueryable().Sum(); + Assert.Equal((double)3, val); + } + + [Fact] + public void Sum8() + { + var val = (new double?[] { 0, 2, 1 }).AsQueryable().Sum(); + Assert.Equal((double)3, val); + } + + [Fact] + public void Sum9() + { + var val = (new decimal[] { 0, 2, 1 }).AsQueryable().Sum(); + Assert.Equal((decimal)3, val); + } + + [Fact] + public void Sum10() + { + var val = (new decimal?[] { 0, 2, 1 }).AsQueryable().Sum(); + Assert.Equal((decimal)3, val); + } + + [Fact] + public void Sum11() + { + var val = (new int[] { 0, 2, 1 }).AsQueryable().Sum(n => n); + Assert.Equal((int)3, val); + } + + [Fact] + public void Sum12() + { + var val = (new int?[] { 0, 2, 1 }).AsQueryable().Sum(n => n); + Assert.Equal((int)3, val); + } + + [Fact] + public void Sum13() + { + var val = (new long[] { 0, 2, 1 }).AsQueryable().Sum(n => n); + Assert.Equal((long)3, val); + } + + [Fact] + public void Sum14() + { + var val = (new long?[] { 0, 2, 1 }).AsQueryable().Sum(n => n); + Assert.Equal((long)3, val); + } + + [Fact] + public void Sum15() + { + var val = (new float[] { 0, 2, 1 }).AsQueryable().Sum(n => n); + Assert.Equal((float)3, val); + } + + [Fact] + public void Sum16() + { + var val = (new float?[] { 0, 2, 1 }).AsQueryable().Sum(n => n); + Assert.Equal((float)3, val); + } + + [Fact] + public void Sum17() + { + var val = (new double[] { 0, 2, 1 }).AsQueryable().Sum(n => n); + Assert.Equal((double)3, val); + } + + [Fact] + public void Sum18() + { + var val = (new double?[] { 0, 2, 1 }).AsQueryable().Sum(n => n); + Assert.Equal((double)3, val); + } + + [Fact] + public void Sum19() + { + var val = (new decimal[] { 0, 2, 1 }).AsQueryable().Sum(n => n); + Assert.Equal((decimal)3, val); + } + + [Fact] + public void Sum20() + { + var val = (new decimal?[] { 0, 2, 1 }).AsQueryable().Sum(n => n); + Assert.Equal((decimal)3, val); + } + + [Fact] + public void Average1() + { + var val = (new int[] { 0, 2, 1 }).AsQueryable().Average(); + Assert.Equal((double)1, val); + } + + [Fact] + public void Average2() + { + var val = (new int?[] { 0, 2, 1 }).AsQueryable().Average(); + Assert.Equal((double)1, val); + } + + [Fact] + public void Average3() + { + var val = (new long[] { 0, 2, 1 }).AsQueryable().Average(); + Assert.Equal((double)1, val); + } + + [Fact] + public void Average4() + { + var val = (new long?[] { 0, 2, 1 }).AsQueryable().Average(); + Assert.Equal((double)1, val); + } + + [Fact] + public void Average5() + { + var val = (new float[] { 0, 2, 1 }).AsQueryable().Average(); + Assert.Equal((float)1, val); + } + + [Fact] + public void Average6() + { + var val = (new float?[] { 0, 2, 1 }).AsQueryable().Average(); + Assert.Equal((float)1, val); + } + + [Fact] + public void Average7() + { + var val = (new double[] { 0, 2, 1 }).AsQueryable().Average(); + Assert.Equal((double)1, val); + } + + [Fact] + public void Average8() + { + var val = (new double?[] { 0, 2, 1 }).AsQueryable().Average(); + Assert.Equal((double)1, val); + } + + [Fact] + public void Average9() + { + var val = (new decimal[] { 0, 2, 1 }).AsQueryable().Average(); + Assert.Equal((decimal)1, val); + } + + [Fact] + public void Average10() + { + var val = (new decimal?[] { 0, 2, 1 }).AsQueryable().Average(); + Assert.Equal((decimal)1, val); + } + + [Fact] + public void Average11() + { + var val = (new int[] { 0, 2, 1 }).AsQueryable().Average(n => n); + Assert.Equal((double)1, val); + } + + [Fact] + public void Average12() + { + var val = (new int?[] { 0, 2, 1 }).AsQueryable().Average(n => n); + Assert.Equal((double)1, val); + } + + [Fact] + public void Average13() + { + var val = (new long[] { 0, 2, 1 }).AsQueryable().Average(n => n); + Assert.Equal((double)1, val); + } + + [Fact] + public void Average14() + { + var val = (new long?[] { 0, 2, 1 }).AsQueryable().Average(n => n); + Assert.Equal((double)1, val); + } + + [Fact] + public void Average15() + { + var val = (new float[] { 0, 2, 1 }).AsQueryable().Average(n => n); + Assert.Equal((float)1, val); + } + + [Fact] + public void Average16() + { + var val = (new float?[] { 0, 2, 1 }).AsQueryable().Average(n => n); + Assert.Equal((float)1, val); + } + + [Fact] + public void Average17() + { + var val = (new double[] { 0, 2, 1 }).AsQueryable().Average(n => n); + Assert.Equal((double)1, val); + } + + [Fact] + public void Average18() + { + var val = (new double?[] { 0, 2, 1 }).AsQueryable().Average(n => n); + Assert.Equal((double)1, val); + } + + [Fact] + public void Average19() + { + var val = (new decimal[] { 0, 2, 1 }).AsQueryable().Average(n => n); + Assert.Equal((decimal)1, val); + } + + [Fact] + public void Average20() + { + var val = (new decimal?[] { 0, 2, 1 }).AsQueryable().Average(n => n); + Assert.Equal((decimal)1, val); + } + + [Fact] + public void Aggregate1() + { + var val = (new int[] { 0, 2, 1 }).AsQueryable().Aggregate((n1, n2) => n1 + n2); + Assert.Equal((int)3, val); + } + + [Fact] + public void Aggregate2() + { + var val = (new int[] { 0, 2, 1 }).AsQueryable().Aggregate("", (n1, n2) => n1 + n2.ToString()); + Assert.Equal("021", val); + } + + [Fact] + public void Aggregate3() + { + var val = (new int[] { 0, 2, 1 }).AsQueryable().Aggregate(0L, (n1, n2) => n1 + n2, n => n.ToString()); + Assert.Equal("3", val); + } + } +} + + diff --git a/src/System.Linq.Queryable/tests/System.Linq.Queryable.Tests.csproj b/src/System.Linq.Queryable/tests/System.Linq.Queryable.Tests.csproj new file mode 100644 index 000000000000..d6a14cb98351 --- /dev/null +++ b/src/System.Linq.Queryable/tests/System.Linq.Queryable.Tests.csproj @@ -0,0 +1,30 @@ + + + + + Debug + AnyCPU + {7B88D79B-B799-4116-A7D0-AED572540CD4} + Library + System.Linq.Queryable.Tests + System.Linq.Queryable.Tests + + + + + + + + + + + + + + + {be12b753-c130-4b68-86e3-877f1aee52c0} + System.Linq.Queryable + + + + \ No newline at end of file diff --git a/src/System.Linq.Queryable/tests/packages.config b/src/System.Linq.Queryable/tests/packages.config new file mode 100644 index 000000000000..a53f48fb9923 --- /dev/null +++ b/src/System.Linq.Queryable/tests/packages.config @@ -0,0 +1,21 @@ + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file