Mercurial > pub > bltoolkit
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; + } + } +}