You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
{{ message }}
Repository navigation
Under NativeAOT, DeepClone over KeyValuePair elements with a value-type key or value throws TypeInitializationException (regression from #82) #92
The fix for #82 (PR #91) deep clones KeyValuePair<TKey, TValue> elements through a cloner that it builds with reflection (DeepClone/DeepCloneContainerExtensions.cs, PairCloner<T>, around lines 143–153):
Under NativeAOT, MakeGenericType cannot produce an instantiation over value types unless the compiler already generated it.
Building the library with -p:IsAotCompatible=true reports IL3050 at that line.
The failure happens in a static initializer, so it surfaces as TypeInitializationException. Every later clone of that element type in the process then fails the same way.
Repro (NativeAOT, linux-x64, net10.0)
new List<KeyValuePair<int, int>> { new(1, 2) }.DeepClone().ToList() → TypeInitializationException
dest.DeepCloneFrom((IReadOnlyDictionary<int, Foo>)dict) into a List<KeyValuePair<int, Foo>> → TypeInitializationException
List<KeyValuePair<string, Foo>> works. Both type arguments are reference types, so the AOT compiler can fall back to shared canonical code.
Before #91 these calls returned the pairs without cloning them. For AOT and trimmed consumers, the shallow-copy bug has become a crash.
Suggested fix
Clone pairs without MakeGenericType:
Add typed overloads so the compiler binds pair sequences statically:
Drop the reflection path, or keep it only for pairs reached through an open generic T, guarded by RuntimeFeature.IsDynamicCodeSupported, with the shallow behaviour as the fallback.
Acceptance:
The library builds with IsAotCompatible=true without IL3050.
Priority: Medium. It only affects NativeAOT consumers, but there it turns a shallow-copy bug into a TypeInitializationException that poisons that element type for the rest of the process. The library also stops being AOT-clean (IL3050).
Area / suggested assignment:DeepCloneContainerExtensions (PairCloner<T>)
Suggested next step: add typed KeyValuePair<TKey, TValue> overloads and drop or guard the MakeGenericType path. Add an IsAotCompatible=true build to CI so this can't regress silently.
Activity
matt-edmondson commentedon Sep 29, 2026
Triage
TypeInitializationExceptionthat poisons that element type for the rest of the process. The library also stops being AOT-clean (IL3050).DeepCloneContainerExtensions(PairCloner<T>)Suggested next step: add typed
KeyValuePair<TKey, TValue>overloads and drop or guard theMakeGenericTypepath. Add anIsAotCompatible=truebuild to CI so this can't regress silently.Generated by Claude Code