本文介绍了在拉姆达前pression替换参数的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

考虑到这一点code:

 公共类Foo
{
    公众诠释一个{搞定;组; }
    公众诠释B {搞定;组; }
}私人无效测试()
{
    清单<富> FOOS =新的List<富>();
    foos.Add(新的Foo());
    foos.Add(新的Foo());
    防爆pression<&Func键LT;富,INT>> exp0 = F => F.A * f.b;
    防爆pression<&Func键LT; INT>> EXP1 =()=> FOOS [0] .A * FOOS [0] .B;
    防爆pression<&Func键LT; INT>> EXP2 =()=> FOOS [1] .A * FOOS [1] .B;
}

你怎么能采取 exp0 并把它变成两位前pressions等同于 EXP1 EXP2 。请注意,我不希望只是评估 exp0 每个 FOOS ,而是得到两个新的前pressions。

[更新]

基本上,我希望能够扩展或扁平化传递给一个的LINQ 扩展方法的前pression如总和成一个前pression每件枚举,因为这些枚举将是静态的,因为我已经有code,上面写着前pressions不带参数(和然后把它们转化成另一种语言)。

我使用了 MetadataToken 为具有特定属性(在这种情况下属性引用 A b 会有这个属性),并用它与相关的C#性能到另一种语言的变量的字典:

 富富=新的Foo();
防爆pression<&Func键LT; INT>> EXP =()=> foo.a * foo.a + foo.b;
字符串RESULT1 =调用getResult(EXP); //得到v_001 * v_001 + v_002清单<富>敌人=新的List<富>();
foes.Add(新的Foo());
foes.Add(新的Foo());
防爆pression<&Func键LT; INT>> EXP2 =()=> foes.Sum(F => F.A * F.A + f.b);
字符串结果2 =调用getResult(EXP2); //应该得到(v_001 * v_001 + v_002)+(v_003 * v_003 + v_004)


解决方案

我会做这种方式:

写参数替代前pression-游客的操纵原来的前pression如下:


  1. 摆脱了参数的不完全从拉姆达签名想要的。

  2. 替换参数的所有使用与所需的索引前pression。

下面是一个快速和肮脏的样品我刮起了基于我在一个不同的问题:

 公共静态类ParameterReplacer
{
    //产生前pression等同于'前pression
    //除了与目标前pression替换成'源'参数。
    公共静态防爆pression< TOutput>更换< TInput,TOutput>
                    (防爆pression< TInput>前pression,
                    ParameterEx pression源,
                    防爆pression目标)
    {
        返回新ParameterReplacerVisitor< TOutput>(源,目标)
                    .VisitAndConvert(如pression);
    }    私有类ParameterReplacerVisitor< TOutput> :防爆pressionVisitor
    {
        私人ParameterEx pression _source;
        私人防爆pression _target;        公共ParameterReplacerVisitor
                (ParameterEx pression源,防爆pression目标)
        {
            _source =来源;
            _target =目标;
        }        内部防爆pression< TOutput> VisitAndConvert< T>(防爆pression< T>根)
        {
            返回(前pression< TOutput>)VisitLambda(根);
        }        保护覆盖防爆pression VisitLambda< T>(防爆pression< T>节点)
        {
            //别碰所有的参数,除了我们要替换的。
            VAR参数= node.Parameters
                                 。凡(P =>!P = _source);            返回前pression.Lambda< TOutput>(参观(node.Body),参数);
        }        保护覆盖防爆pression VisitParameter(ParameterEx pression节点)
        {
            //与目标替换源,访问其他PARAMS如常。
            返回节点== _source? _target:base.VisitParameter(节点);
        }
    }
}

为您的方案使用(测试):

  VAR zeroIndexIndexer =前pression.MakeIndex
        (防爆pression.Constant(FOOS)
         typeof运算(列表<富>)的getProperty(项目)。
         新的[] {防爆pression.Constant(0)});
//的下面的ToString()如下所示:
//()= GT; (值(System.Collections.Generic.List`1 [App.Foo])。项目[0] .A
// *值(System.Collections.Generic.List`1 [App.Foo])。项目[0] .B)
VAR exp1Clone = ParameterReplacer.Replace<&Func键LT;富,INT>中Func键< INT>>
                  (exp0,exp0.Parameters.Single(),zeroIndexIndexer);

Considering this code:

public class Foo
{
    public int a { get; set; }
    public int b { get; set; }
}

private void Test()
{
    List<Foo> foos = new List<Foo>();
    foos.Add(new Foo());
    foos.Add(new Foo());
    Expression<Func<Foo, int>> exp0 = f => f.a * f.b;
    Expression<Func<int>> exp1 = () => foos[0].a * foos[0].b;
    Expression<Func<int>> exp2 = () => foos[1].a * foos[1].b;
}

How can you take exp0 and turn it into two expressions identical to exp1 and exp2. Note that I don't want to just evaluate exp0 for each Foo in foos, but instead get two new expressions.

[Update]:

Basically, I want to be able to expand or "flatten" an expression passed to a Linq extension method such as Sum into one expression per item in the enumeration since these enumerations will be static, and because I already have code that reads expressions that don't take parameters (and then turns them into another language).

I'm using the MetadataToken as a references to properties that have a certain attribute (in this case a and b would have this attribute) and using it with a dictionary that correlates C# properties to another language's variables:

Foo foo = new Foo();
Expression<Func<int>> exp = () => foo.a * foo.a + foo.b;
string result1 = GetResult(exp); // gets "v_001 * v_001 + v_002"

List<Foo> foes = new List<Foo>();
foes.Add(new Foo());
foes.Add(new Foo());
Expression<Func<int>> exp2 = () => foes.Sum(f => f.a * f.a + f.b);
string result2 = GetResult(exp2); // should get "(v_001 * v_001 + v_002) + (v_003 * v_003 + v_004)"
解决方案

I would do it this way:

Write a parameter-replacer expression-visitor that manipulates the original expression as follows:

  1. Gets rid of the parameter you don't want entirely from the lambda signature.
  2. Replaces all uses of the parameter with the desired indexer expression.

Here's a quick and dirty sample I whipped up based on my earlier answer on a different question:

public static class ParameterReplacer
{
    // Produces an expression identical to 'expression'
    // except with 'source' parameter replaced with 'target' expression.     
    public static Expression<TOutput> Replace<TInput, TOutput>
                    (Expression<TInput> expression,
                    ParameterExpression source,
                    Expression target)
    {
        return new ParameterReplacerVisitor<TOutput>(source, target)
                    .VisitAndConvert(expression);
    }

    private class ParameterReplacerVisitor<TOutput> : ExpressionVisitor
    {
        private ParameterExpression _source;
        private Expression _target;

        public ParameterReplacerVisitor
                (ParameterExpression source, Expression target)
        {
            _source = source;
            _target = target;
        }

        internal Expression<TOutput> VisitAndConvert<T>(Expression<T> root)
        {
            return (Expression<TOutput>)VisitLambda(root);
        }

        protected override Expression VisitLambda<T>(Expression<T> node)
        {
            // Leave all parameters alone except the one we want to replace.
            var parameters = node.Parameters
                                 .Where(p => p != _source);

            return Expression.Lambda<TOutput>(Visit(node.Body), parameters);
        }

        protected override Expression VisitParameter(ParameterExpression node)
        {
            // Replace the source with the target, visit other params as usual.
            return node == _source ? _target : base.VisitParameter(node);
        }
    }
}

Usage for your scenario (tested):

var zeroIndexIndexer = Expression.MakeIndex
        (Expression.Constant(foos),
         typeof(List<Foo>).GetProperty("Item"), 
         new[] { Expression.Constant(0) });


// .ToString() of the below looks like the following: 
//  () =>    (value(System.Collections.Generic.List`1[App.Foo]).Item[0].a
//         *  value(System.Collections.Generic.List`1[App.Foo]).Item[0].b)
var exp1Clone = ParameterReplacer.Replace<Func<Foo, int>, Func<int>>
                  (exp0, exp0.Parameters.Single(), zeroIndexIndexer);

这篇关于在拉姆达前pression替换参数的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持!

10-11 06:41