我正在使用System.Ling.Expressions API創建和編譯一個表達式。編譯工作正常,但在某些情況下,當運行編譯的lambda時,我會遇到無法解釋的NullReferenceExceptions甚至是System.Security.Verification異常。作爲參考,此項目的目的是爲.NET類型創建和編譯自定義序列化器函數。奇怪的異常編譯動態構建的表達式
以下是對於debuginfo軟拋出一個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)
}
異常被調用#Lambda3,這是從WriteCollectionElements反覆調用中拋出。 WriteCollectionElements的實現如下:
static void WriteCollectionElements<T>(IEnumerable<T> collection, IWriter writer, Action<IWriter, T> writeAction)
{
foreach (var element in collection)
{
writeAction(writer, element);
}
}
從這個函數內部調試,我已經確定,收集,作家的WriteAction和元素都是非空時,拋出異常。 ,我傳遞給編譯拉姆達的說法是:
new { a = new[] { 20, 10 }, b = 2 }
而且奇怪的是,如果我刪除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)
}
我在Windows 7上運行.NET Framework 4(至少這是我的構建目標),VS快遞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())
}
);
但是,我不喜歡單獨編制的每一個表情,所以我最終乾脆只用WriteCollectionElements功能做掉通過Expression.Loop,Expression.Break等動態創建foreach循環。
因此,我不再被阻止,但仍然非常好奇。
是例外可再現?它是否總是發生在同一個「元素」? –
@DanielHilgarth是的,每次都會發生異常。在處理相同的元素時總是會發生這種情況,在本例中爲20. – ChaseMedallion
也許您可以使用最少的代碼創建一個小的示例應用程序來重現此行爲? –