我正在构建一个表达式来动态构建一些代码,以便为我的模型对象进行高效的手动JSON序列化,而无需在我更改模型时随时更新它。我的表达式在下面抛出以下异常。
在分配变量之前,我是否需要首先声明变量?
System.InvalidOperationException:'变量' sw'类型' System.IO.StringWriter'引用范围'',但未定义'
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
应该将SenExpressions与正文分开传递。
答案 0 :(得分:1)
您创建了一个sw参数stringWriterExpression
(应该称之为stringWriterParameter
)并且您在身体中使用了它,但是您没有将其定义为lambda参数。
我认为您需要使用Expression.Variable
代替Expression.Parameter
,并将其作为ParameterExpression[]
添加到您的阻止。