【发布时间】: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