202 lines
6.1 KiB
C#
202 lines
6.1 KiB
C#
using System;
|
|
using System.Collections;
|
|
using System.Collections.Generic;
|
|
using System.Linq.Expressions;
|
|
using System.Reflection;
|
|
using System.Runtime.CompilerServices;
|
|
|
|
namespace System.Linq
|
|
{
|
|
// Token: 0x02000046 RID: 70
|
|
internal class QueryableTransformer : ExpressionTransformer
|
|
{
|
|
// Token: 0x06000431 RID: 1073 RVA: 0x00013E84 File Offset: 0x00012084
|
|
protected override Expression VisitMethodCall(MethodCallExpression methodCall)
|
|
{
|
|
if (QueryableTransformer.IsQueryableExtension(methodCall.Method))
|
|
{
|
|
return this.ReplaceQueryableMethod(methodCall);
|
|
}
|
|
return base.VisitMethodCall(methodCall);
|
|
}
|
|
|
|
// Token: 0x06000432 RID: 1074 RVA: 0x00013EB0 File Offset: 0x000120B0
|
|
protected override Expression VisitLambda(LambdaExpression lambda)
|
|
{
|
|
return lambda;
|
|
}
|
|
|
|
// Token: 0x06000433 RID: 1075 RVA: 0x00013EB4 File Offset: 0x000120B4
|
|
protected override Expression VisitConstant(ConstantExpression constant)
|
|
{
|
|
IQueryableEnumerable queryableEnumerable = constant.Value as IQueryableEnumerable;
|
|
if (queryableEnumerable == null)
|
|
{
|
|
return constant;
|
|
}
|
|
return Expression.Constant(queryableEnumerable.GetEnumerable());
|
|
}
|
|
|
|
// Token: 0x06000434 RID: 1076 RVA: 0x00013EE0 File Offset: 0x000120E0
|
|
private static bool IsQueryableExtension(MethodInfo method)
|
|
{
|
|
return QueryableTransformer.HasExtensionAttribute(method) && method.GetParameters()[0].ParameterType.IsAssignableTo(typeof(IQueryable));
|
|
}
|
|
|
|
// Token: 0x06000435 RID: 1077 RVA: 0x00013F18 File Offset: 0x00012118
|
|
private static bool HasExtensionAttribute(MethodInfo method)
|
|
{
|
|
return method.GetCustomAttributes(typeof(ExtensionAttribute), false).Length > 0;
|
|
}
|
|
|
|
// Token: 0x06000436 RID: 1078 RVA: 0x00013F30 File Offset: 0x00012130
|
|
private MethodCallExpression ReplaceQueryableMethod(MethodCallExpression old)
|
|
{
|
|
Expression expression = null;
|
|
if (old.Object != null)
|
|
{
|
|
expression = this.Visit(old.Object);
|
|
}
|
|
MethodInfo methodInfo = QueryableTransformer.ReplaceQueryableMethod(old.Method);
|
|
ParameterInfo[] parameters = methodInfo.GetParameters();
|
|
Expression[] array = new Expression[old.Arguments.Count];
|
|
for (int i = 0; i < array.Length; i++)
|
|
{
|
|
array[i] = QueryableTransformer.UnquoteIfNeeded(this.Visit(old.Arguments[i]), parameters[i].ParameterType);
|
|
}
|
|
return new MethodCallExpression(expression, methodInfo, array.ToReadOnlyCollection<Expression>());
|
|
}
|
|
|
|
// Token: 0x06000437 RID: 1079 RVA: 0x00013FC8 File Offset: 0x000121C8
|
|
private static Expression UnquoteIfNeeded(Expression expression, Type delegateType)
|
|
{
|
|
if (expression.NodeType != ExpressionType.Quote)
|
|
{
|
|
return expression;
|
|
}
|
|
LambdaExpression lambdaExpression = (LambdaExpression)((UnaryExpression)expression).Operand;
|
|
if (lambdaExpression.Type == delegateType)
|
|
{
|
|
return lambdaExpression;
|
|
}
|
|
return expression;
|
|
}
|
|
|
|
// Token: 0x06000438 RID: 1080 RVA: 0x00014004 File Offset: 0x00012204
|
|
private static Type GetTargetDeclaringType(MethodInfo method)
|
|
{
|
|
return (method.DeclaringType != typeof(Queryable)) ? method.DeclaringType : typeof(Enumerable);
|
|
}
|
|
|
|
// Token: 0x06000439 RID: 1081 RVA: 0x0001403C File Offset: 0x0001223C
|
|
private static MethodInfo ReplaceQueryableMethod(MethodInfo method)
|
|
{
|
|
MethodInfo matchingMethod = QueryableTransformer.GetMatchingMethod(method, QueryableTransformer.GetTargetDeclaringType(method));
|
|
if (matchingMethod != null)
|
|
{
|
|
return matchingMethod;
|
|
}
|
|
throw new InvalidOperationException(string.Format("There is no method {0} on type {1} that matches the specified arguments", method.Name, method.DeclaringType.FullName));
|
|
}
|
|
|
|
// Token: 0x0600043A RID: 1082 RVA: 0x00014080 File Offset: 0x00012280
|
|
private static MethodInfo GetMatchingMethod(MethodInfo method, Type declaring)
|
|
{
|
|
MethodInfo[] methods = declaring.GetMethods();
|
|
int i = 0;
|
|
while (i < methods.Length)
|
|
{
|
|
MethodInfo methodInfo = methods[i];
|
|
if (!QueryableTransformer.MethodMatch(methodInfo, method))
|
|
{
|
|
i++;
|
|
}
|
|
else
|
|
{
|
|
if (method.IsGenericMethod)
|
|
{
|
|
return methodInfo.MakeGenericMethodFrom(method);
|
|
}
|
|
return methodInfo;
|
|
}
|
|
}
|
|
return null;
|
|
}
|
|
|
|
// Token: 0x0600043B RID: 1083 RVA: 0x000140D4 File Offset: 0x000122D4
|
|
private static bool MethodMatch(MethodInfo candidate, MethodInfo method)
|
|
{
|
|
if (candidate.Name != method.Name)
|
|
{
|
|
return false;
|
|
}
|
|
if (!QueryableTransformer.HasExtensionAttribute(candidate))
|
|
{
|
|
return false;
|
|
}
|
|
Type[] parameterTypes = method.GetParameterTypes();
|
|
if (parameterTypes.Length != candidate.GetParameters().Length)
|
|
{
|
|
return false;
|
|
}
|
|
if (method.IsGenericMethod)
|
|
{
|
|
if (!candidate.IsGenericMethod)
|
|
{
|
|
return false;
|
|
}
|
|
if (candidate.GetGenericArguments().Length != method.GetGenericArguments().Length)
|
|
{
|
|
return false;
|
|
}
|
|
candidate = candidate.MakeGenericMethodFrom(method);
|
|
}
|
|
if (!QueryableTransformer.TypeMatch(candidate.ReturnType, method.ReturnType))
|
|
{
|
|
return false;
|
|
}
|
|
Type[] parameterTypes2 = candidate.GetParameterTypes();
|
|
if (parameterTypes2[0] != QueryableTransformer.GetComparableType(parameterTypes[0]))
|
|
{
|
|
return false;
|
|
}
|
|
for (int i = 1; i < parameterTypes2.Length; i++)
|
|
{
|
|
if (!QueryableTransformer.TypeMatch(parameterTypes2[i], parameterTypes[i]))
|
|
{
|
|
return false;
|
|
}
|
|
}
|
|
return true;
|
|
}
|
|
|
|
// Token: 0x0600043C RID: 1084 RVA: 0x000141B0 File Offset: 0x000123B0
|
|
private static bool TypeMatch(Type candidate, Type type)
|
|
{
|
|
return candidate == type || candidate == QueryableTransformer.GetComparableType(type);
|
|
}
|
|
|
|
// Token: 0x0600043D RID: 1085 RVA: 0x000141C4 File Offset: 0x000123C4
|
|
private static Type GetComparableType(Type type)
|
|
{
|
|
if (type.IsGenericInstanceOf(typeof(IQueryable<>)))
|
|
{
|
|
type = typeof(IEnumerable<>).MakeGenericTypeFrom(type);
|
|
}
|
|
else if (type.IsGenericInstanceOf(typeof(IOrderedQueryable<>)))
|
|
{
|
|
type = typeof(IOrderedEnumerable<>).MakeGenericTypeFrom(type);
|
|
}
|
|
else if (type.IsGenericInstanceOf(typeof(Expression<>)))
|
|
{
|
|
type = type.GetFirstGenericArgument();
|
|
}
|
|
else if (type == typeof(IQueryable))
|
|
{
|
|
type = typeof(IEnumerable);
|
|
}
|
|
return type;
|
|
}
|
|
}
|
|
}
|