栏目分类:
子分类:
返回
名师互学网用户登录
快速导航关闭
当前搜索
当前分类
子分类
实用工具
热门搜索
名师互学网 > IT > 面试经验 > 面试问答

在C#中组合两个Lambda表达式

面试问答 更新时间: 发布时间: IT归档 最新发布 模块sitemap 名妆网 法律咨询 聚返吧 英语巴士网 伯小乐 网商动力

在C#中组合两个Lambda表达式

好; 相当长的代码段,但这是表达式重写 器的入门指南 ;它尚不能处理少数情况(稍后再解决),但它适用于给定的示例以及 许多 其他示例:

using System;using System.Collections.Generic;using System.Linq;using System.Linq.expressions;using System.Text.Regularexpressions;public class GrandParent{    public Parent Parent { get; set; }}public class Parent{    public Child Child { get; set; }    public string Method(string s) { return s + "abc"; }}public class Child{    public string Name { get; set; }}public static class expressionUtils{    public static expression<Func<T1, T3>> Combine<T1, T2, T3>(        this expression<Func<T1, T2>> outer, expression<Func<T2, T3>> inner, bool inline)    {        var invoke = expression.Invoke(inner, outer.Body);        expression body = inline ? new expressionRewriter().AutoInline(invoke) : invoke;        return expression.Lambda<Func<T1, T3>>(body, outer.Parameters);    }}public class expressionRewriter{    internal expression AutoInline(Invocationexpression expression)    {        isLocked = true;        if(expression == null) throw new ArgumentNullException("expression");        Lambdaexpression lambda = (Lambdaexpression)expression.expression;        expressionRewriter childScope = new expressionRewriter(this);        var lambdaParams = lambda.Parameters;        var invokeArgs = expression.Arguments;        if (lambdaParams.Count != invokeArgs.Count) throw new InvalidOperationException("Lambda/invoke mismatch");        for(int i = 0 ; i < lambdaParams.Count; i++) { childScope.Subst(lambdaParams[i], invokeArgs[i]);        }        return childScope.Apply(lambda.Body);    }    public expressionRewriter()    {         subst = new Dictionary<expression, expression>();    }    private expressionRewriter(expressionRewriter parent)    {        if (parent == null) throw new ArgumentNullException("parent");        subst = new Dictionary<expression, expression>(parent.subst);        inline = parent.inline;    }    private bool isLocked, inline;    private readonly Dictionary<expression, expression> subst;    private void CheckLocked() {        if(isLocked) throw new InvalidOperationException( "You cannot alter the rewriter after Apply has been called");    }    public expressionRewriter Subst(expression from,        expression to)    {        CheckLocked();        subst.Add(from, to);        return this;    }    public expressionRewriter Inline() {        CheckLocked();        inline = true;        return this;    }    public expression Apply(expression expression)    {        isLocked = true;        return Walk(expression) ?? expression;    }    private static IEnumerable<expression> CoalesceTerms(        IEnumerable<expression> sourceWithNulls, IEnumerable<expression> replacements)    {        if(sourceWithNulls != null && replacements != null) { using(var left = sourceWithNulls.GetEnumerator()) using (var right = replacements.GetEnumerator()) {     while (left.MoveNext() && right.MoveNext())     {         yield return left.Current ?? right.Current;     } }        }    }    private expression[] Walk(IEnumerable<expression> expressions) {        if(expressions == null) return null;        return expressions.Select(expr => Walk(expr)).ToArray();    }    private static bool HasValue(expression[] expressions)    {        return expressions != null && expressions.Any(expr => expr != null);    }    // returns null if no need to rewrite that branch, otherwise    // returns a re-written branch    private expression Walk(expression expression)    {        if (expression == null) return null;        expression tmp;        if (subst.TryGetValue(expression, out tmp)) return tmp;        switch(expression.NodeType) { case expressionType.Constant: case expressionType.Parameter:     {         return expression; // never a need to rewrite if not already matched     } case expressionType.MemberAccess:     {         Memberexpression me = (Memberexpression)expression;         expression target = Walk(me.expression);         return target == null ? null : expression.MakeMemberAccess(target, me.Member);     } case expressionType.Add: case expressionType.Divide: case expressionType.Multiply: case expressionType.Subtract: case expressionType.AddChecked: case expressionType.MultiplyChecked: case expressionType.SubtractChecked: case expressionType.And: case expressionType.Or: case expressionType.ExclusiveOr: case expressionType.Equal: case expressionType.NotEqual: case expressionType.AndAlso: case expressionType.OrElse: case expressionType.Power: case expressionType.Modulo: case expressionType.GreaterThan: case expressionType.GreaterThanOrEqual: case expressionType.LessThan: case expressionType.LessThanOrEqual: case expressionType.LeftShift: case expressionType.RightShift: case expressionType.Coalesce: case expressionType.ArrayIndex:     {         Binaryexpression binExp = (Binaryexpression)expression;         expression left = Walk(binExp.Left), right = Walk(binExp.Right);         return (left == null && right == null) ? null : expression.MakeBinary(  binExp.NodeType, left ?? binExp.Left, right ?? binExp.Right, binExp.IsLiftedToNull,  binExp.Method, binExp.Conversion);     } case expressionType.Not: case expressionType.UnaryPlus: case expressionType.Negate: case expressionType.NegateChecked: case expressionType.Convert:  case expressionType.ConvertChecked: case expressionType.TypeAs: case expressionType.ArrayLength:     {         Unaryexpression unExp = (Unaryexpression)expression;         expression operand = Walk(unExp.Operand);         return operand == null ? null : expression.MakeUnary(unExp.NodeType, operand,  unExp.Type, unExp.Method);     } case expressionType.Conditional:     {         Conditionalexpression ce = (Conditionalexpression)expression;         expression test = Walk(ce.Test), ifTrue = Walk(ce.IfTrue), ifFalse = Walk(ce.IfFalse);         if (test == null && ifTrue == null && ifFalse == null) return null;         return expression.Condition(test ?? ce.Test, ifTrue ?? ce.IfTrue, ifFalse ?? ce.IfFalse);     } case expressionType.Call:     {         MethodCallexpression mce = (MethodCallexpression)expression;         expression instance = Walk(mce.Object);         expression[] args = Walk(mce.Arguments);         if (instance == null && !HasValue(args)) return null;         return expression.Call(instance, mce.Method, CoalesceTerms(args, mce.Arguments));     } case expressionType.TypeIs:     {         TypeBinaryexpression tbe = (TypeBinaryexpression)expression;         tmp = Walk(tbe.expression);         return tmp == null ? null : expression.TypeIs(tmp, tbe.TypeOperand);     } case expressionType.New:     {         Newexpression ne = (Newexpression)expression;         expression[] args = Walk(ne.Arguments);         if (HasValue(args)) return null;         return ne.Members == null ? expression.New(ne.Constructor, CoalesceTerms(args, ne.Arguments))  : expression.New(ne.Constructor, CoalesceTerms(args, ne.Arguments), ne.Members);     } case expressionType.ListInit:     {         ListInitexpression lie = (ListInitexpression)expression;         Newexpression ctor = (Newexpression)Walk(lie.Newexpression);         var inits = lie.Initializers.Select(init => new         {  Original = init,  NewArgs = Walk(init.Arguments)         }).ToArray();         if (ctor == null && !inits.Any(init => HasValue(init.NewArgs))) return null;         ElementInit[] initArr = inits.Select(init => expression.ElementInit(      init.Original.AddMethod, CoalesceTerms(init.NewArgs, init.Original.Arguments))).ToArray();         return expression.ListInit(ctor ?? lie.Newexpression, initArr);     } case expressionType.NewArrayBounds: case expressionType.NewArrayInit:      case expressionType.Invoke: case expressionType.Lambda: case expressionType.MemberInit: case expressionType.Quote:     throw new NotImplementedException("Not implemented: " + expression.NodeType); default:     throw new NotSupportedException("Not supported: " + expression.NodeType);        }    }}static class Program{    static void Main()    {        expression<Func<GrandParent, Parent>> myFirst = gp => gp.Parent;        expression<Func<Parent, string>> mySecond = p => p.Child.Name;        expression<Func<GrandParent, string>> outputWithInline = myFirst.Combine(mySecond, false);        expression<Func<GrandParent, string>> outputWithoutInline = myFirst.Combine(mySecond, true);        expression<Func<GrandParent, string>> call =     expressionUtils.Combine<GrandParent, Parent, string>(     gp => gp.Parent, p => p.Method(p.Child.Name), true);        unchecked        { expression<Func<double, double>> mathUnchecked =     expressionUtils.Combine<double, double, double>(x => (x * x) + x, x => x - (x / x), true);        }        checked        { expression<Func<double, double>> mathChecked =     expressionUtils.Combine<double, double, double>(x => x - (x * x) , x => (x / x) + x, true);        }        expression<Func<int,int>> bitwise = expressionUtils.Combine<int, int, int>(x => (x & 0x01) | 0x03, x => x ^ 0xFF, true);        expression<Func<int, bool>> logical = expressionUtils.Combine<int, bool, bool>(x => x == 123, x => x != false, true);        expression<Func<int[][], int>> arrayAccess = expressionUtils.Combine<int[][], int[], int>(x => x[0], x => x[0], true);        expression<Func<string, bool>> isTest = expressionUtils.Combine<string,object,bool>(s=>s, s=> s is Regex, true);        expression<Func<List<int>>> f = () => new List<int>(new int[] { 1, 1, 1 }.Length);        expression<Func<string, Regex>> asTest = expressionUtils.Combine<string, object, Regex>(s => s, s => s as Regex, true);        var initTest = expressionUtils.Combine<int, int[], List<int>>(i => new[] {i,i,i},          arr => new List<int>(arr.Length), true);        var anonAndListTest = expressionUtils.Combine<int, int, List<int>>(     i => new { age = i }.age, i => new List<int> {i, i}, true);            }}


转载请注明:文章转载自 www.mshxw.com
本文地址:https://www.mshxw.com/it/442707.html
我们一直用心在做
关于我们 文章归档 网站地图 联系我们

版权所有 (c)2021-2022 MSHXW.COM

ICP备案号:晋ICP备2021003244-6号