Warning: file_get_contents(/data/phpspider/zhask/data//catemap/8/linq/3.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
C# 动态编译的异常生成表达式_C#_Linq_C# 4.0_Expression Trees - Fatal编程技术网

C# 动态编译的异常生成表达式

C# 动态编译的异常生成表达式,c#,linq,c#-4.0,expression-trees,C#,Linq,C# 4.0,Expression Trees,我正在使用System.Ling.Expressions API创建和编译表达式。编译工作正常,但在某些情况下,在运行编译后的lambda时会出现无法解释的NullReferenceException,甚至System.Security.Verification异常。作为参考,本项目的目的是为.NET类型创建和编译自定义序列化程序函数 以下是引发NullReferenceException的表达式的调试信息: .Lambda #Lambda1<System.Action`2[IO.IWri

我正在使用System.Ling.Expressions API创建和编译表达式。编译工作正常,但在某些情况下,在运行编译后的lambda时会出现无法解释的NullReferenceException,甚至System.Security.Verification异常。作为参考,本项目的目的是为.NET类型创建和编译自定义序列化程序函数

以下是引发NullReferenceException的表达式的调试信息:

.Lambda #Lambda1<System.Action`2[IO.IWriter,<>f__AnonymousType1`2[System.Int32[],System.Int32]]>(
    IO.IWriter $writer,
    <>f__AnonymousType1`2[System.Int32[],System.Int32] $t) {
    .Block() {
        .Invoke (.Lambda #Lambda2<System.Action`2[IO.IWriter,System.Int32[]]>)(
            $writer,
            $t.a);
        .Invoke (.Lambda #Lambda3<System.Action`2[IO.IWriter,System.Int32]>)(
            $writer,
            $t.b)
    }
}

.Lambda #Lambda2<System.Action`2[IO.IWriter,System.Int32[]]>(
    IO.IWriter $writer,
    System.Int32[] $t) {
    .Block() {
        .Invoke (.Lambda #Lambda4<System.Action`2[IO.IWriter,System.Int32]>)(
            $writer,
            .Call System.Linq.Enumerable.Count((System.Collections.Generic.IEnumerable`1[System.Int32])$t));
        .Call IO.SerializerHelpers.WriteCollectionElements(
            (System.Collections.Generic.IEnumerable`1[System.Int32])$t,
            $writer,
            .Lambda #Lambda3<System.Action`2[IO.IWriter,System.Int32]>)
    }
}

.Lambda #Lambda3<System.Action`2[IO.IWriter,System.Int32]>(
    IO.IWriter $writer,
    System.Int32 $t) {
    .Call $writer.WriteInt($t)
}

.Lambda #Lambda4<System.Action`2[IO.IWriter,System.Int32]>(
    IO.IWriter $w,
    System.Int32 $count) {
    .Call $w.BeginWritingCollection($count)
}
同样奇怪的是,如果我删除b属性并重新生成序列化程序函数,一切都会正常工作。在这种情况下,序列化程序的DebugInfo为:

.Lambda #Lambda1<System.Action`2[IO.IWriter,<>f__AnonymousType5`1[System.Int32[]]]>(
    IO.IWriter $writer,
    <>f__AnonymousType5`1[System.Int32[]] $t) {
    .Block() {
        .Invoke (.Lambda #Lambda2<System.Action`2[IO.IWriter,System.Int32[]]>)(
            $writer,
            $t.a)
    }
}

.Lambda #Lambda2<System.Action`2[IO.IWriter,System.Int32[]]>(
    IO.IWriter $writer,
    System.Int32[] $t) {
    .Block() {
        .Invoke (.Lambda #Lambda3<System.Action`2[IO.IWriter,System.Int32]>)(
            $writer,
            .Call System.Linq.Enumerable.Count((System.Collections.Generic.IEnumerable`1[System.Int32])$t));
        .Call IO.SerializerHelpers.WriteCollectionElements(
            (System.Collections.Generic.IEnumerable`1[System.Int32])$t,
            $writer,
            .Lambda #Lambda4<System.Action`2[IO.IWriter,System.Int32]>)
    }
}

.Lambda #Lambda3<System.Action`2[IO.IWriter,System.Int32]>(
    IO.IWriter $w,
    System.Int32 $count) {
    .Call $w.BeginWritingCollection($count)
}

.Lambda #Lambda4<System.Action`2[IO.IWriter,System.Int32]>(
    IO.IWriter $writer,
    System.Int32 $t) {
    .Call $writer.WriteInt($t)
}
.Lambda#Lambda1(
IO.IWriter$writer,
f_u匿名类型5`1[System.Int32[]]$t){
.Block(){
.Invoke(.Lambda#Lambda2)(
$writer,
$t.a)
}
}
.Lambda#Lambda2(
IO.IWriter$writer,
System.Int32[]$t){
.Block(){
.Invoke(.Lambda#Lambda3)(
$writer,
.Call System.Linq.Enumerable.Count((System.Collections.Generic.IEnumerable`1[System.Int32])$t);
.调用IO.SerializerHelpers.WriteCollectionElements(
(System.Collections.Generic.IEnumerable`1[System.Int32])$t,
$writer,
.Lambda#Lambda4)
}
}
.Lambda#Lambda 3(
IO.IWriter$w,
System.Int32$count){
.调用$w.BeginWritingCollection($count)
}
.Lambda#Lambda 4(
IO.IWriter$writer,
System.Int32$t){
.Call$writer.WriteInt($t)
}
我正在Windows7上运行.NETFramework4(至少这是我的构建目标),而不是Express C#2010

有没有人知道可能会出现什么问题,或者下一步尝试调试的步骤?如果有帮助的话,我很乐意发布更多信息

编辑:据我所知,我已经找到了解决这个bug的方法,尽管我还不太了解它为什么会发生。在生成我上面发布的表达式的代码中,我有以下内容:

MethodInfo writeCollectionElementsMethod = // the methodInfo for WriteCollectionElements with .MakeGenericMethod() called with typeof(T)
Expression<Action<IWriter, T> writeActionExpression = // I created this expression separately
ParameterExpression writerParameter, enumerableTParameter = // parameters of type IWriter and IEnumerable<T>, respectively

// make an expression to invoke the method
var methodCallExpression = Expression.Call(
    instance: null, // static
    method: writeCollectionElementsMethod,
    arguments: new[] {
        enumerableTParameter,
        writerParameter,
        // passing in this expression correctly would produce the weird error in some cases as described above
        writeActionExpression
    }
);

// make an expression to invoke the method
var methodCallExpressionV2 = Expression.Call(
    instance: null, // static
    method: writeCollectionElementsMethod,
    arguments: new[] {
        enumerableTParameter,
        writerParameter,
        // this did not cause the bug
        Expression.Constant(writeActionExpression.Compile())
    }
);
MethodInfo writeCollectionElementsMethod=//使用typeof(T)调用.MakeGenericMethod()的WriteCollectionElements的MethodInfo

Expression如果在C#resharper中手动构建操作,则会抱怨Lambda1和Lambda2隐式捕获clousure中的变量

Action<IWriter, int> lambda4 = ( (IWriter writer, int length) => writer.BeginWritingCollection(length));
Action<IWriter, int> lambda3 = ( (IWriter writer, int value) => writer.WriteInt(value));
Action<IWriter, int[]> lambda2 = ( (IWriter writer, int[] value) =>
   {
      lambda4(writer, ((IEnumerable<int>) value).Count());
      WriteCollectionElements((IEnumerable<int>)value, writer, lambda3);
   });
Action<IWriter, TheData> lambda1 = ((writer, data) =>
   {
      lambda2(writer, data.a);
      lambda3(writer, data.b);
   });
class TheData { int[] a; int b; }
Action lambda4=((IWriter writer,int-length)=>writer.BeginWritingCollection(length));
Action lambda3=((IWriter writer,int-value)=>writer.WriteInt(value));
操作lambda2=((IWriter编写器,int[]值)=>
{
lambda4(writer,((IEnumerable)值).Count());
WriteCollectionElements((IEnumerable)值,writer,lambda3);
});
操作lambda1=((写入程序、数据)=>
{
lambda2(编写器,data.a);
lambda3(writer,data.b);
});
为数据{int[]a;int b;}初始化
在这种情况下,resharper声明:
lambda2表达式上的“隐式捕获闭包:lambda2”
lambda1表达式上的“隐式捕获闭包:lambda4”

对此的解释是和。如果删除了WriteCollectionElements的行,警告将消失。实际上,JIT编译为内部表达式调用创建一个包装类,捕获writer和匿名类型的值,以便将BeginWritingCollection的操作传递给WriteCollectionElements静态方法

解决方案是将lambda2中的语句内联到lambda1中

Action<IWriter, int> lambda4 = ( (IWriter writer, int length) => writer.BeginWritingCollection(length));
Action<IWriter, int> lambda3 = ( (IWriter writer, int value) => writer.WriteInt(value));
Action<IWriter, TheData> lambda1 = ((writer, data) =>
   {
      lambda4(writer, ((IEnumerable<int>) value.a).Count());
      WriteCollectionElements((IEnumerable<int>)value.a, writer, lambda3);
      lambda3(writer, data.b);
   });
class TheData { int[] a; int b; }
Action lambda4=((IWriter writer,int-length)=>writer.BeginWritingCollection(length));
Action lambda3=((IWriter writer,int-value)=>writer.WriteInt(value));
操作lambda1=((写入程序、数据)=>
{
lambda4(writer,((IEnumerable)value.a.Count());
WriteCollectionElements((IEnumerable)value.a,writer,lambda3);
lambda3(writer,data.b);
});
为数据{int[]a;int b;}初始化

异常是否可复制?同一
元素是否总是发生这种情况?@DanielHilgarth是的,每次都会发生异常。在处理同一个元素时总是会发生这种情况,在本例中是20。也许你可以用最少的代码创建一个小样本应用程序来重现这种行为?@dexpert你能进一步解释吗?WriteCollectionElements是一种通用方法。我认为Lambda3属于Action类型(不是)。然后,我使用MakeGenericMethod()获取WriteCollectionElements的版本,其中T为int。为什么这是非法的?@DanielHilgarth抱歉,我没有提交示例应用程序的原因是,构建此应用程序的代码很难从我的代码库的其余部分中解脱出来。由于我不再被阻止,我不认为自己会很快解决这个问题,特别是因为错误的原因似乎与我不了解的非常具体的情况有关。编译这两组操作,并查看[reflector | dotPeek | justDecompile | ILSpy]中的DLL您将看到创建的包装器类型。我阅读了链接并理解了这个问题,但我没有看到它与我使用表达式(与原始操作/函数相反)的关系。编译表达式时,您的表达式将转换为等效操作。您无法“执行”expressionOk,但我想我迷路的地方是对我遇到的NullReferenceException的解释。lambda捕获是如何导致此异常的?您的一个示例是否复制了这一点?捕获状态时,您还存储了对编写器的引用。如果该writer设置为null,那么下次运行序列化程序时将出现异常
Action<IWriter, int> lambda4 = ( (IWriter writer, int length) => writer.BeginWritingCollection(length));
Action<IWriter, int> lambda3 = ( (IWriter writer, int value) => writer.WriteInt(value));
Action<IWriter, int[]> lambda2 = ( (IWriter writer, int[] value) =>
   {
      lambda4(writer, ((IEnumerable<int>) value).Count());
      WriteCollectionElements((IEnumerable<int>)value, writer, lambda3);
   });
Action<IWriter, TheData> lambda1 = ((writer, data) =>
   {
      lambda2(writer, data.a);
      lambda3(writer, data.b);
   });
class TheData { int[] a; int b; }
Action<IWriter, int> lambda4 = ( (IWriter writer, int length) => writer.BeginWritingCollection(length));
Action<IWriter, int> lambda3 = ( (IWriter writer, int value) => writer.WriteInt(value));
Action<IWriter, TheData> lambda1 = ((writer, data) =>
   {
      lambda4(writer, ((IEnumerable<int>) value.a).Count());
      WriteCollectionElements((IEnumerable<int>)value.a, writer, lambda3);
      lambda3(writer, data.b);
   });
class TheData { int[] a; int b; }