我正在尝试使用 Reflection.Emit 创建一个名为 EvaluateOnCondition 的方法 . 我使用 Linq Expressions 生成方法的主体,并且我想使用 LambdaExpression 的 CompileToMethod 方法将表达式的 IL 注入 EvaluateOnCondition ,但是当我执行 CompileToMethod 方法时,我收到以下错误:
CompileToMethod无法编译常量'某个值',因为它是一个非平凡的值,例如活动对象 . 而是创建一个可以构造此值的表达式树 .
这就是我想要做的:
MethodBuilder evaluateOnCondition = tb.DefineMethod("EvaluateOnCondition", MethodAttributes.Public | MethodAttributes.Static, typeof(bool), new[] { typeof(object), typeof(object) });
onCondition.CompileToMethod(evaluateOnCondition); // throw the error
onCondition变量是LambdaExpression,是使用Linq表达式创建的比较条件,表示以下伪代码: obj1.prop1 == obj2.prop1
这是我的StackTrace:
at System.Linq.Expressions.Compiler.BoundConstants.EmitCacheConstants(LambdaCompiler lc)
at System.Linq.Expressions.Compiler.LambdaCompiler..ctor(AnalyzedTree tree, LambdaExpression lambda, MethodBuilder method)
at System.Linq.Expressions.Compiler.LambdaCompiler.Compile(LambdaExpression lambda, MethodBuilder method, DebugInfoGenerator debugInfoGenerator)
at System.Linq.Expressions.LambdaExpression.CompileToMethodInternal(MethodBuilder method, DebugInfoGenerator debugInfoGenerator)
at System.Linq.Expressions.LambdaExpression.CompileToMethod(MethodBuilder method)
at Integra.Space.Language.Runtime.LanguageTypeBuilder.CreateEqualsMethod(TypeBuilder tb, Type parentType, Type typeOtherSource, Boolean isSecondSource, LambdaExpression onCondition) in C:\Users\Oscar\Documents\GitHubVisualStudio\Integra.Space.Language\Integra.Space.Language\Runtime\TypeBuilders\LanguageTypeBuilder.cs:line 343
at Integra.Space.Language.Runtime.LanguageTypeBuilder.CreateTypeBuilder(List`1 listOfFields, Type parentType, Boolean overrideGetHashCodeMethod, Boolean overrideEquals, Type typeOtherSource, Boolean isSecondSource, LambdaExpression onCondition) in C:\Users\Oscar\Documents\GitHubVisualStudio\Integra.Space.Language\Integra.Space.Language\Runtime\TypeBuilders\LanguageTypeBuilder.cs:line 165
at Integra.Space.Language.Runtime.LanguageTypeBuilder.CompileExtractedEventDataComparerTypeForJoin(Type parentType, Type typeOfTheOtherSource, Boolean isSecondSource, LambdaExpression onCondition) in C:\Users\Oscar\Documents\GitHubVisualStudio\Integra.Space.Language\Integra.Space.Language\Runtime\TypeBuilders\LanguageTypeBuilder.cs:line 92
at Integra.Space.Language.Runtime.ObservableConstructor.CreateProjectionExpression(PlanNode plans) in C:\Users\Oscar\Documents\GitHubVisualStudio\Integra.Space.Language\Integra.Space.Language\Runtime\ObservableConstructor.cs:line 3033
at Integra.Space.Language.Runtime.ObservableConstructor.CreateExpressionNode(PlanNode actualNode, Expression leftNode, Expression rightNode) in C:\Users\Oscar\Documents\GitHubVisualStudio\Integra.Space.Language\Integra.Space.Language\Runtime\ObservableConstructor.cs:line 358
at Integra.Space.Language.Runtime.ObservableConstructor.GenerateExpressionTree(PlanNode plan) in C:\Users\Oscar\Documents\GitHubVisualStudio\Integra.Space.Language\Integra.Space.Language\Runtime\ObservableConstructor.cs:line 304
at Integra.Space.Language.Runtime.ObservableConstructor.GenerateExpressionTree(PlanNode plan) in C:\Users\Oscar\Documents\GitHubVisualStudio\Integra.Space.Language\Integra.Space.Language\Runtime\ObservableConstructor.cs:line 313
at Integra.Space.Language.Runtime.ObservableConstructor.GenerateExpressionTree(PlanNode plan) in C:\Users\Oscar\Documents\GitHubVisualStudio\Integra.Space.Language\Integra.Space.Language\Runtime\ObservableConstructor.cs:line 299
at Integra.Space.Language.Runtime.ObservableConstructor.GenerateExpressionTree(PlanNode plan) in C:\Users\Oscar\Documents\GitHubVisualStudio\Integra.Space.Language\Integra.Space.Language\Runtime\ObservableConstructor.cs:line 299
at Integra.Space.Language.Runtime.ObservableConstructor.GenerateExpressionTree(PlanNode plan) in C:\Users\Oscar\Documents\GitHubVisualStudio\Integra.Space.Language\Integra.Space.Language\Runtime\ObservableConstructor.cs:line 313
at Integra.Space.Language.Runtime.ObservableConstructor.GenerateExpressionTree(PlanNode plan) in C:\Users\Oscar\Documents\GitHubVisualStudio\Integra.Space.Language\Integra.Space.Language\Runtime\ObservableConstructor.cs:line 313
at Integra.Space.Language.Runtime.ObservableConstructor.CreateObservableJoin(PlanNode actualNode) in C:\Users\Oscar\Documents\GitHubVisualStudio\Integra.Space.Language\Integra.Space.Language\Runtime\ObservableConstructor.cs:line 936
onCondition变量的Debug视图
.Block(System.Boolean $variable) {
.Try {
.Block() {
.If (
True
) {
.Call System.Diagnostics.Debug.WriteLine("Start of the equal operation '==': ")
} .Else {
.Default(System.Void)
};
$variable = (System.Object).Block(System.Object $variable) {
.If (.Constant<System.Reflection.RuntimePropertyInfo>(System.Object _adapter_Name) == null) { // 12 line
$variable = .Default(System.Object)
} .Else {
.Try {
.Block() {
.If (
True
) {
.Call System.Diagnostics.Debug.WriteLine("Start of the get property operation: _adapter_Name")
} .Else {
.Default(System.Void)
};
$variable = $NewScopeParameter_0._adapter_Name;
.If (
True
) {
.Call System.Diagnostics.Debug.WriteLine("End of the get property operation: _adapter_Name")
} .Else {
.Default(System.Void)
};
.Default(System.Void)
}
} .Catch (System.Exception $var1) {
.Block() {
.Call System.Diagnostics.Debug.WriteLine("No fue posible obtener la propiedad _adapter_Name, error en la linea: 0 columna: 162 con t1.@event.Adapter.Name")
;
.Throw .New Integra.Space.Language.Exceptions.RuntimeException(
"RuntimeException: Line: 0, Column: 162, Instruction: t1.@event.Adapter.Name, Error: RE5: Error with the get property operation",
$var1)
}
}
};
$variable
} == (System.Object).Block(System.Object $variable) {
.If (.Constant<System.Reflection.RuntimePropertyInfo>(System.Object _adapter_Name) == null) {
$variable = .Default(System.Object)
} .Else {
.Try {
.Block() {
.If (
True
) {
.Call System.Diagnostics.Debug.WriteLine("Start of the get property operation: _adapter_Name")
} .Else {
.Default(System.Void)
};
$variable = $NewScopeParameter_1._adapter_Name;
.If (
True
) {
.Call System.Diagnostics.Debug.WriteLine("End of the get property operation: _adapter_Name")
} .Else {
.Default(System.Void)
};
.Default(System.Void)
}
} .Catch (System.Exception $var2) {
.Block() {
.Call System.Diagnostics.Debug.WriteLine("No fue posible obtener la propiedad _adapter_Name, error en la linea: 0 columna: 188 con t2.@event.Adapter.Name")
;
.Throw .New Integra.Space.Language.Exceptions.RuntimeException(
"RuntimeException: Line: 0, Column: 188, Instruction: t2.@event.Adapter.Name, Error: RE5: Error with the get property operation",
$var2)
}
}
};
$variable
};
.If (
True
) {
.Call System.Diagnostics.Debug.WriteLine("End of the equal operation")
} .Else {
.Default(System.Void)
};
.Default(System.Void)
}
} .Catch (System.Exception $var3) {
.Block() {
.Call System.Diagnostics.Debug.WriteLine("Error con la expresion de igualdad en la linea: 0 columna: 167 con t1.@event.Adapter.Name == t2.@event.Adapter.Name")
;
.Throw .New Integra.Space.Language.Exceptions.RuntimeException(
"RuntimeException: Line: 0, Column: 167, Instruction: t1.@event.Adapter.Name == t2.@event.Adapter.Name, Error: RE43: Error with the equal operation '=='",
$var3)
}
};
$variable
}
我怀疑这个核心错误被抛出了 .
BTW:C#中的 non-trivial value 是什么?我怎么能解决这个问题?
如果您需要更多信息,请告诉我
2 回答
一般来说
null
,bool
,char
,sbyte
,byte
,short
,ushort
,int
,uint
,long
,ulong
,float
,double
,decimal
,string
,Type
,MethodBase
都可以 . 其他一切都不是 .你可以从VariableBinder.VisitConstant开始看到它:
转到
AddReference
是不好的,并且从长远来看会导致您看到的异常 .然后你可以查看ILGen.CanEmitConstant并查看已完成的测试 .
为什么会这样?因为您正在尝试在方法内编译一个对象 . 虽然这通常可以使用
LambdaExpression.Compile()
,因为对象并没有真正保存在方法中,而只是对生活在内存中的对象的引用,如果使用CompileToMethod()
,.NET必须能够保存副本方法内部的对象,因为CompileToMethod()(和MethodBuilder
/TypeBuilder
/AssemblyBuilder
)能够生成新的dll . 这些dll可以与其他机器共享/加载几天后(它们是"normal" dlls),因此它们不受支持 . 显然,这并没有注意到并非所有.NET基元类型都受支持 . 缺少IntPtr
和UIntPtr
)以及一些特殊类型,如Type
(在.NET中有特殊处理) .我解决了这个问题,如果你想使用 CompileToMethod 方法将表达式转换为方法的IL主体,基本上你不能将反射用于表达式树 . 现在这是我的onCondition调试视图:
You can see the 12 line I've removed the use of Reflection for get the property _adapter_Name.