【问题标题】:Expression tree: variable referenced but not defined表达式树:引用但未定义的变量
【发布时间】:2018-01-06 00:55:23
【问题描述】:

我正在构建一个表达式来动态构建一些代码,以便为我的模型对象进行高效的手动 JSON 序列化,而无需在我更改模型时随时更新它。我的表达式在下面抛出以下异常。

在分配变量之前是否需要一个表达式来首先声明变量?

System.InvalidOperationException: 'System.IO.StringWriter' 类型的变量 'sw' 从范围 '' 引用,但未定义'

public static Func<T, string> ConstructJsonParserFunction<T>()
    {
        List<Expression> methodBodyExpressions = new List<Expression>();
        ParameterExpression methodParameter = Expression.Parameter(typeof(T), "entity");
        ParameterExpression stringWriterExpression = Expression.Variable(typeof(StringWriter), "sw");
        ParameterExpression jsonTextWriterExpression = Expression.Variable(typeof(JsonTextWriter), "writer");
        ConstructorInfo jsonTextWriterConstructor = typeof(JsonTextWriter).GetConstructor(new Type[] { typeof(TextWriter) });
        MethodInfo jsonTextWriterMethod_WriteStartObject = typeof(JsonTextWriter).GetMethod("WriteStartObject");
        MethodInfo jsonTextWriterMethod_WritePropertyName = typeof(JsonTextWriter).GetMethods()
            .Where(mi => mi.Name == "WritePropertyName" && mi.GetParameters().Length == 1 && mi.GetParameters()[0].Name == "name")
            .First();

        Dictionary<Type, MethodInfo> jsonTextWriterMethods_WriteValue = new Dictionary<Type, MethodInfo>();

        foreach (MethodInfo method in typeof(JsonTextWriter).GetMethods().Where(mi => mi.Name == "WriteValue" && mi.GetParameters().Length == 1))
        {
            jsonTextWriterMethods_WriteValue[method.GetParameters()[0].ParameterType] = method;
        }

        MethodInfo jsonTextWriterMethod_WriteEndObject = typeof(JsonTextWriter).GetMethod("WriteEndObject");
        MethodInfo stringWriterMethod_ToString = typeof(StringWriter).GetMethods()
            .Where(mi => mi.Name == "ToString" && mi.GetParameters().Length == 0)
            .First();

        methodBodyExpressions.Add(stringWriterExpression);
        methodBodyExpressions.Add(jsonTextWriterExpression);
        methodBodyExpressions.Add(Expression.Assign(stringWriterExpression, Expression.New(typeof(StringWriter))));
        methodBodyExpressions.Add(Expression.Assign(jsonTextWriterExpression, Expression.New(jsonTextWriterConstructor, stringWriterExpression)));
        methodBodyExpressions.Add(Expression.Call(jsonTextWriterExpression, jsonTextWriterMethod_WriteStartObject));

        foreach (PropertyInfo property in typeof(T).GetProperties().Where(p => Attribute.IsDefined(p, typeof(JsonPropertyAttribute))))
        {
            methodBodyExpressions.Add(Expression.Call(jsonTextWriterExpression, jsonTextWriterMethod_WritePropertyName, Expression.Constant(property.Name)));
            methodBodyExpressions.Add(Expression.Call(jsonTextWriterExpression, jsonTextWriterMethods_WriteValue[property.PropertyType], Expression.Property(methodParameter, property)));
        }

        methodBodyExpressions.Add(Expression.Call(jsonTextWriterExpression, jsonTextWriterMethod_WriteEndObject));
        methodBodyExpressions.Add(Expression.Call(stringWriterExpression, stringWriterMethod_ToString));

        BlockExpression block = Expression.Block(methodBodyExpressions);

        return Expression.Lambda<Func<T, string>>(block, methodParameter).Compile();
    }

调试视图字符串:

.Block() {
    $sw;
    $writer;
    $sw = .New System.IO.StringWriter();
    $writer = .New Newtonsoft.Json.JsonTextWriter($sw);
    .Call $writer.WriteStartObject();
    .Call $writer.WritePropertyName("CompanyId");
    .Call $writer.WriteValue($entity.CompanyId);
    .Call $writer.WritePropertyName("Name");
    .Call $writer.WriteValue($entity.Name);
    .Call $writer.WriteEndObject();
    .Call $sw.ToString()
}

编辑

解决方案:正如 NetMage 所说,局部变量需要两件事才能被赋值。首先,使用Expression.Variable(type, "debugVarName") 创建ParameterExpression。其次,Expression.Block 应该与正文分开传递 ParameterExpressions。

【问题讨论】:

    标签: c# expression


    【解决方案1】:

    您创建了一个 sw 参数 stringWriterExpression(应该将其称为 stringWriterParameter)并在您的正文中使用它,但您没有将 is 定义为 lambda 参数。

    我认为您需要使用 Expression.Variable 而不是 Expression.Parameter 并将其作为 ParameterExpression[] 添加到您的块中。

    【讨论】:

      猜你喜欢
      • 2015-03-09
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多