diff Source/Data/Linq/Builder/MethodCallBuilder.cs @ 0:f990fcb411a9

Копия текущей версии из github
author cin
date Thu, 27 Mar 2014 21:46:09 +0400
parents
children
line wrap: on
line diff
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/Source/Data/Linq/Builder/MethodCallBuilder.cs	Thu Mar 27 21:46:09 2014 +0400
@@ -0,0 +1,125 @@
+using System;
+using System.Linq;
+using System.Linq.Expressions;
+
+namespace BLToolkit.Data.Linq.Builder
+{
+	using BLToolkit.Linq;
+
+	abstract class MethodCallBuilder : ISequenceBuilder
+	{
+		public int BuildCounter { get; set; }
+
+		public bool CanBuild(ExpressionBuilder builder, BuildInfo buildInfo)
+		{
+			if (buildInfo.Expression.NodeType == ExpressionType.Call)
+				return CanBuildMethodCall(builder, (MethodCallExpression)buildInfo.Expression, buildInfo);
+			return false;
+		}
+
+		public IBuildContext BuildSequence(ExpressionBuilder builder, BuildInfo buildInfo)
+		{
+			return BuildMethodCall(builder, (MethodCallExpression)buildInfo.Expression, buildInfo);
+		}
+
+		public SequenceConvertInfo Convert(ExpressionBuilder builder, BuildInfo buildInfo, ParameterExpression param)
+		{
+			return Convert(builder, (MethodCallExpression)buildInfo.Expression, buildInfo, param);
+		}
+
+		public bool IsSequence(ExpressionBuilder builder, BuildInfo buildInfo)
+		{
+			return builder.IsSequence(new BuildInfo(buildInfo, ((MethodCallExpression)buildInfo.Expression).Arguments[0]));
+		}
+
+		protected abstract bool                CanBuildMethodCall(ExpressionBuilder builder, MethodCallExpression methodCall, BuildInfo buildInfo);
+		protected abstract IBuildContext       BuildMethodCall   (ExpressionBuilder builder, MethodCallExpression methodCall, BuildInfo buildInfo);
+		protected abstract SequenceConvertInfo Convert           (ExpressionBuilder builder, MethodCallExpression methodCall, BuildInfo buildInfo, ParameterExpression param);
+
+		protected static Expression ConvertMethod(
+			MethodCallExpression methodCall,
+			int                  sourceTypeNumber,
+			SequenceConvertInfo  info,
+			ParameterExpression  param,
+			Expression           expression)
+		{
+			if (expression == methodCall && param != null && param.Type != info.Parameter.Type)
+			{
+				var types = methodCall.Method.GetGenericArguments();
+				var mgen  = methodCall.Method.GetGenericMethodDefinition();
+
+				types[sourceTypeNumber] = info.Parameter.Type;
+
+				var args = methodCall.Arguments.ToArray();
+
+				args[0] = info.Expression;
+
+				for (var i = 1; i < args.Length; i++)
+				{
+					var arg = args[i].Unwrap();
+
+					if (arg.NodeType == ExpressionType.Lambda)
+					{
+						var l = (LambdaExpression)arg;
+
+						if (l.Parameters.Any(a => a == param))
+						{
+							args[i] = Expression.Lambda(
+								l.Body.Convert(ex => ConvertMethod(methodCall, sourceTypeNumber, info, param, ex)),
+								info.Parameter);
+
+							return Expression.Call(methodCall.Object, mgen.MakeGenericMethod(types), args);
+						}
+					}
+				}
+			}
+
+			if (expression == methodCall.Arguments[0])
+				return info.Expression;
+
+			switch (expression.NodeType)
+			{
+				case ExpressionType.Parameter :
+
+					if (info.ExpressionsToReplace != null)
+						foreach (var item in info.ExpressionsToReplace)
+							if (expression == item.Path || expression == param && item.Path.NodeType == ExpressionType.Parameter)
+								return item.Expr;
+					break;
+
+				case ExpressionType.MemberAccess :
+
+					if (info.ExpressionsToReplace != null)
+					{
+						foreach (var item in info.ExpressionsToReplace)
+						{
+							var ex1 = expression;
+							var ex2 = item.Path;
+
+							while (ex1.NodeType == ex2.NodeType)
+							{
+								if (ex1.NodeType == ExpressionType.Parameter)
+									return ex1 == ex2 || info.Parameter == ex2? item.Expr : expression;
+
+								if (ex2.NodeType != ExpressionType.MemberAccess)
+									break;
+
+								var ma1 = (MemberExpression)ex1;
+								var ma2 = (MemberExpression)ex2;
+
+								if (ma1.Member != ma2.Member)
+									break;
+
+								ex1 = ma1.Expression;
+								ex2 = ma2.Expression;
+							}
+						}
+					}
+
+					break;
+			}
+
+			return expression;
+		}
+	}
+}