JsonSerializerOptions.MemberAccessorStrategy shouldn't use Reflection.Emit when IsDynamicCodeCompiled is false (original) (raw)

When trimming a Blazor WASM app, the last usage of Reflection.Emit (after fixing #38678) is coming from System.Text.Json.Serialization.JsonSerializerOptions:

internal MemberAccessor MemberAccessorStrategy
{
get
{
if (_memberAccessorStrategy == null)
{
#if NETFRAMEWORK |
_memberAccessorStrategy = new ReflectionEmitMemberAccessor();
#else
_memberAccessorStrategy = new ReflectionMemberAccessor();
#endif
}
return _memberAccessorStrategy;
}
}

However, on Mono WASM, RuntimeFeature.IsDynamicCodeCompiled is always false, so using Reflection.Emit is probably a waste, and it brings in a decent amount of code. In my investigations I find it removing ~50KB of IL if we trim this usage of Reflection.Emit.

We should change this code to something more like:

    internal MemberAccessor MemberAccessorStrategy
    {
        get
        {
            if (_memberAccessorStrategy == null)
            {

#if NETFRAMEWORK || NETCOREAPP if (RuntimeFeature.IsDynamicCodeCompiled) { _memberAccessorStrategy = new ReflectionEmitMemberAccessor(); } else { _memberAccessorStrategy = new ReflectionMemberAccessor(); } #else _memberAccessorStrategy = new ReflectionMemberAccessor(); #endif }

            return _memberAccessorStrategy;
        }
    }

With changing the code to the above, on a default template Blazor WASM app, I am seeing size savings of:

Build Size
master 3,366,912 bytes
#38729 3,039,232 bytes
#38729 + this change 2,990,080 bytes

So almost a 50 KB savings by allowing the removing all usages of System.Reflection.Emit.

cc @steveharter @layomia @vitek-karas @marek-safar