首页 文章

CompileToMethod无法编译常量'<some value>'因为它是一个非平凡的值,例如活动对象

提问于
浏览
2

我正在尝试使用 Reflection.Emit 创建一个名为 EvaluateOnCondition 的方法 . 我使用 Linq Expressions 生成方法的主体,并且我想使用 LambdaExpressionCompileToMethod 方法将表达式的 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
}

我怀疑这个核心错误被抛出了 .

BoundConstants line 133

BTW:C#中的 non-trivial value 是什么?我怎么能解决这个问题?

如果您需要更多信息,请告诉我

2 回答

  • 0

    C#中的非平凡 Value 是什么?我怎么能解决这个问题?*

    一般来说 nullboolcharsbytebyteshortushortintuintlongulongfloatdoubledecimalstringTypeMethodBase 都可以 . 其他一切都不是 .

    你可以从VariableBinder.VisitConstant开始看到它:

    if (ILGen.CanEmitConstant(node.Value, node.Type))
    {
        return node;
    }
    this._constants.Peek().AddReference(node.Value, node.Type);
    

    转到 AddReference 是不好的,并且从长远来看会导致您看到的异常 .

    然后你可以查看ILGen.CanEmitConstant并查看已完成的测试 .

    为什么会这样?因为您正在尝试在方法内编译一个对象 . 虽然这通常可以使用 LambdaExpression.Compile() ,因为对象并没有真正保存在方法中,而只是对生活在内存中的对象的引用,如果使用 CompileToMethod() ,.NET必须能够保存副本方法内部的对象,因为CompileToMethod()(和 MethodBuilder / TypeBuilder / AssemblyBuilder )能够生成新的dll . 这些dll可以与其他机器共享/加载几天后(它们是"normal" dlls),因此它们不受支持 . 显然,这并没有注意到并非所有.NET基元类型都受支持 . 缺少 IntPtrUIntPtr )以及一些特殊类型,如 Type (在.NET中有特殊处理) .

  • 5

    我解决了这个问题,如果你想使用 CompileToMethod 方法将表达式转换为方法的IL主体,基本上你不能将反射用于表达式树 . 现在这是我的onCondition调试视图:

    .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 (True == False) { // 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 (True == False) {
                        $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
    }
    

    You can see the 12 line I've removed the use of Reflection for get the property _adapter_Name.

相关问题