表达式、常量列表、编译器生成的类
Expression, Constant List, Compiler generated calss
我有这个简单的代码:
public void MyWhere( Expression<Func<T, bool>> predicate)
{
}
List<string> Indexes2 = new List<string>();
Indexes2.Add("abc");
MyWhere(a=>Index2.Contains(a.a1));
在解析表达式时,Index2 显示为 ConstantExpression。然后类似于 this site 和其他地方的许多示例,我有这种方法来解析 ConatantExpression 的值:
private static object ConstantValue(ConstantExpression member)
{
// source:
var objectMember = Expression.Convert(member, typeof(object));
var getterLambda = Expression.Lambda<Func<object>>(objectMember);
var getter = getterLambda.Compile();
return getter();
}
问题出在这个方法的 return 类型中,return 值的类型是:
{名称 = "<>c__DisplayClass38_0" 全名 = "S_Common.A_Dictionary`2+<>c__DisplayClass38_0[[S_Common.StringIndex, S_Common, 版本=1.0.0.0,文化=中性,PublicKeyToken=null],[DummyTestApp.test,DummyTestApp,版本=1.0.0.0,文化=中性,PublicKeyToken=null]]"}
在 QuickWatch 中可以找到底层列表,但几乎无法在代码中引用它。
当您“关闭”局部变量时,会生成一个隐藏的 class。您在 ConstantExpression
中看到的是对这个隐藏 class.
实例的引用
这个:
public void MyWhere<T>(Expression<Func<T, bool>> predicate)
{
}
public void M()
{
List<string> Indexes2 = new List<string>();
Indexes2.Add("abc");
MyWhere<String>(a => Indexes2.Contains(a));
}
编译为
[CompilerGenerated]
private sealed class <>c__DisplayClass1_0
{
public List<string> Indexes2;
}
public void MyWhere<T>(Expression<Func<T, bool>> predicate)
{
}
public void M()
{
<>c__DisplayClass1_0 <>c__DisplayClass1_ = new <>c__DisplayClass1_0();
<>c__DisplayClass1_.Indexes2 = new List<string>();
<>c__DisplayClass1_.Indexes2.Add("abc");
ParameterExpression parameterExpression = Expression.Parameter(typeof(string), "a");
MemberExpression instance = Expression.Field(Expression.Constant(<>c__DisplayClass1_, typeof(<>c__DisplayClass1_0)), FieldInfo.GetFieldFromHandle((RuntimeFieldHandle)/*OpCode not supported: LdMemberToken*/));
MethodInfo method = (MethodInfo)MethodBase.GetMethodFromHandle((RuntimeMethodHandle)/*OpCode not supported: LdMemberToken*/, typeof(List<string>).TypeHandle);
Expression[] array = new Expression[1];
array[0] = parameterExpression;
MethodCallExpression body = Expression.Call(instance, method, array);
ParameterExpression[] array2 = new ParameterExpression[1];
array2[0] = parameterExpression;
MyWhere(Expression.Lambda<Func<string, bool>>(body, array2));
}
(参见 sharplab)
有趣的部分是 private sealed class <>c__DisplayClass1_0
和 Expression.Constant(<>c__DisplayClass1_, typeof(<>c__DisplayClass1_0))
。
这个隐藏的class是隐藏的。您只能通过反射与之交互。
您的问题并不是很容易解决。对于给出的 具体 示例:
public static void MyWhere<T>(Expression<Func<T, bool>> predicate)
{
var body = predicate.Body;
// .Contains(...)
var contains = body as MethodCallExpression;
// Indexes2
var field = contains.Object;
// Need boxing only for value types
var boxIfNecessary = field.Type.IsValueType ? (Expression)Expression.Convert(field, typeof(object)) : field;
var lambda = Expression.Lambda<Func<object>>(boxIfNecessary);
var compiled = lambda.Compile();
// Indexes of type List<string>()
var value = compiled();
}
例如:
MyWhere<string>(a => Enumerable.Contains(Indexes2, a));
会破坏我给的密码。
我有这个简单的代码:
public void MyWhere( Expression<Func<T, bool>> predicate)
{
}
List<string> Indexes2 = new List<string>();
Indexes2.Add("abc");
MyWhere(a=>Index2.Contains(a.a1));
在解析表达式时,Index2 显示为 ConstantExpression。然后类似于 this site 和其他地方的许多示例,我有这种方法来解析 ConatantExpression 的值:
private static object ConstantValue(ConstantExpression member)
{
// source:
var objectMember = Expression.Convert(member, typeof(object));
var getterLambda = Expression.Lambda<Func<object>>(objectMember);
var getter = getterLambda.Compile();
return getter();
}
问题出在这个方法的 return 类型中,return 值的类型是:
{名称 = "<>c__DisplayClass38_0" 全名 = "S_Common.A_Dictionary`2+<>c__DisplayClass38_0[[S_Common.StringIndex, S_Common, 版本=1.0.0.0,文化=中性,PublicKeyToken=null],[DummyTestApp.test,DummyTestApp,版本=1.0.0.0,文化=中性,PublicKeyToken=null]]"}
在 QuickWatch 中可以找到底层列表,但几乎无法在代码中引用它。
当您“关闭”局部变量时,会生成一个隐藏的 class。您在 ConstantExpression
中看到的是对这个隐藏 class.
这个:
public void MyWhere<T>(Expression<Func<T, bool>> predicate)
{
}
public void M()
{
List<string> Indexes2 = new List<string>();
Indexes2.Add("abc");
MyWhere<String>(a => Indexes2.Contains(a));
}
编译为
[CompilerGenerated]
private sealed class <>c__DisplayClass1_0
{
public List<string> Indexes2;
}
public void MyWhere<T>(Expression<Func<T, bool>> predicate)
{
}
public void M()
{
<>c__DisplayClass1_0 <>c__DisplayClass1_ = new <>c__DisplayClass1_0();
<>c__DisplayClass1_.Indexes2 = new List<string>();
<>c__DisplayClass1_.Indexes2.Add("abc");
ParameterExpression parameterExpression = Expression.Parameter(typeof(string), "a");
MemberExpression instance = Expression.Field(Expression.Constant(<>c__DisplayClass1_, typeof(<>c__DisplayClass1_0)), FieldInfo.GetFieldFromHandle((RuntimeFieldHandle)/*OpCode not supported: LdMemberToken*/));
MethodInfo method = (MethodInfo)MethodBase.GetMethodFromHandle((RuntimeMethodHandle)/*OpCode not supported: LdMemberToken*/, typeof(List<string>).TypeHandle);
Expression[] array = new Expression[1];
array[0] = parameterExpression;
MethodCallExpression body = Expression.Call(instance, method, array);
ParameterExpression[] array2 = new ParameterExpression[1];
array2[0] = parameterExpression;
MyWhere(Expression.Lambda<Func<string, bool>>(body, array2));
}
(参见 sharplab)
有趣的部分是 private sealed class <>c__DisplayClass1_0
和 Expression.Constant(<>c__DisplayClass1_, typeof(<>c__DisplayClass1_0))
。
这个隐藏的class是隐藏的。您只能通过反射与之交互。
您的问题并不是很容易解决。对于给出的 具体 示例:
public static void MyWhere<T>(Expression<Func<T, bool>> predicate)
{
var body = predicate.Body;
// .Contains(...)
var contains = body as MethodCallExpression;
// Indexes2
var field = contains.Object;
// Need boxing only for value types
var boxIfNecessary = field.Type.IsValueType ? (Expression)Expression.Convert(field, typeof(object)) : field;
var lambda = Expression.Lambda<Func<object>>(boxIfNecessary);
var compiled = lambda.Compile();
// Indexes of type List<string>()
var value = compiled();
}
例如:
MyWhere<string>(a => Enumerable.Contains(Indexes2, a));
会破坏我给的密码。