Variable 'x.Sub' of type 'SubType' referenced from scope '' but it is not defined error

后端 未结 1 570
时光说笑
时光说笑 2021-01-14 08:26

Check this fiddle for the error: https://dotnetfiddle.net/tlz4Qg

I have two classes like this:

public class ParentType{
    private ParentType(){}

          


        
1条回答
  •  时光说笑
    2021-01-14 09:03

    The cause of the problem in question is the line

    currentParameter = Expression.Parameter(currentType, currentParameter.Name + "." + property.Name);
    

    inside VisitNew method.

    With your sample, it creates a new parameter called "x.Sub", so if we mark the parameters with {}, the actual result is

    Sub = new SubType()
    {
        Id = {x.Sub}.Id
    }, 
    

    rather than expected

    Sub = new SubType()
    {
        Id = {x}.Sub.Id
    },
    

    In general you should not create new ParameterExpressions except when remapping lambda expressions. And all newly created parameters should be passed to Expression.Lambda call, otherwise they will be considered "not defined".

    Also please note that the visitor code has some assumptions which doesn't hold in general. For instance

    var xOriginal = Expression.PropertyOrField(currentParameter, x.Name);
    

    won't work inside nested new, because there you need access to a member of the x parameter like x.Sub.Id rather than x.Id. Which is basically the corersonding expression from NewExpression.Arguments.

    Processing nested lambda expressions or collection type members and LINQ methods with expression visitors requires much more state control. While converting simple nested anonymous new expression like in the sample does not even need a ExpressionVisitor, because it could easily be achieved with simple recursive method like this:

    public static Expression> Transform(this Expression> source)
    {
        return Expression.Lambda>(
            Transform(source.Body, typeof(Tout)),
            source.Parameters);
    }
    
    static Expression Transform(Expression source, Type type)
    {
        if (source.Type != type && source is NewExpression newExpr && newExpr.Members.Count > 0)
        {
            return Expression.MemberInit(Expression.New(type), newExpr.Members
                .Select(m => type.GetProperty(m.Name))
                .Zip(newExpr.Arguments, (m, e) => Expression.Bind(m, Transform(e, m.PropertyType))));
        }
        return source;
    }
    

    0 讨论(0)
提交回复
热议问题