// MIT License - Copyright (c) 2025 wallstop // Full license text: https://github.com/wallstop/unity-helpers/blob/main/LICENSE #if !((UNITY_WEBGL && !UNITY_EDITOR) || ENABLE_IL2CPP) #define EMIT_DYNAMIC_IL #define SUPPORT_EXPRESSION_COMPILE #endif namespace WallstopStudios.UnityHelpers.Core.Helper { using System; using System.Collections.Generic; using System.Reflection; using System.Runtime.CompilerServices; #if !SINGLE_THREADED using System.Collections.Concurrent; #endif // ReflectionHelpers.Factory.cs - Delegate creation and strategy management // See ReflectionHelpers.cs for full architecture documentation public static partial class ReflectionHelpers { /// /// Specifies which implementation strategy to use for creating reflection delegates. /// /// /// The tries strategies in order: Expressions → DynamicIl → Reflection. /// Failed strategies are tracked in a blocklist to avoid repeated attempts. /// internal enum ReflectionDelegateStrategy { [Obsolete("Use a concrete strategy value.", false)] Unknown = 0, Expressions = 1, DynamicIl = 2, Reflection = 3, } /// /// Internal factory responsible for creating, caching, and managing reflection delegates. /// /// /// /// For each member type (FieldInfo, PropertyInfo, MethodInfo, ConstructorInfo), this factory: /// /// /// Checks if a delegate is already cached for the requested strategy /// Checks if the strategy has previously failed (blocklist) /// Attempts to create a new delegate using the strategy /// On failure, marks the strategy as unavailable and tries the next /// Caches successful delegates for future use /// /// /// The factory uses to uniquely identify cache entries /// by both member and strategy, allowing different strategies to coexist in the cache. /// /// private static class DelegateFactory { private const byte StrategyUnavailableSentinel = 0; private readonly struct CapabilityKey : IEquatable> { internal CapabilityKey(T member, ReflectionDelegateStrategy strategy) { Member = member; Strategy = strategy; } internal T Member { get; } internal ReflectionDelegateStrategy Strategy { get; } public bool Equals(CapabilityKey other) { return Strategy == other.Strategy && EqualityComparer.Default.Equals(Member, other.Member); } public override bool Equals(object obj) { if (obj is CapabilityKey other) { return Equals(other); } return false; } public override int GetHashCode() { return Objects.HashCode(Member, Strategy); } } private sealed class StrategyHolder { internal StrategyHolder( ReflectionDelegateStrategy strategy, object memberKey, Type delegateType ) { Strategy = strategy; MemberKey = memberKey; DelegateType = delegateType; } internal ReflectionDelegateStrategy Strategy { get; } internal object MemberKey { get; } internal Type DelegateType { get; } internal static StrategyHolder Create( CapabilityKey key, Type delegateType ) { object memberKey = key.Member is null ? NullMemberKey : key.Member; return new StrategyHolder(key.Strategy, memberKey, delegateType); } private static readonly object NullMemberKey = new(); } private static readonly ConditionalWeakTable< Delegate, StrategyHolder > DelegateStrategyTable = new(); #if !SINGLE_THREADED private static readonly ConcurrentDictionary< CapabilityKey, Func > FieldGetters = new(); private static readonly ConcurrentDictionary< CapabilityKey, byte > FieldGetterStrategyBlocklist = new(); private static readonly ConcurrentDictionary< CapabilityKey, Action > FieldSetters = new(); private static readonly ConcurrentDictionary< CapabilityKey, byte > FieldSetterStrategyBlocklist = new(); private static readonly ConcurrentDictionary< CapabilityKey, Func > StaticFieldGetters = new(); private static readonly ConcurrentDictionary< CapabilityKey, byte > StaticFieldGetterStrategyBlocklist = new(); private static readonly ConcurrentDictionary< CapabilityKey, Action > StaticFieldSetters = new(); private static readonly ConcurrentDictionary< CapabilityKey, byte > StaticFieldSetterStrategyBlocklist = new(); private static readonly ConcurrentDictionary< CapabilityKey, Func > PropertyGetters = new(); private static readonly ConcurrentDictionary< CapabilityKey, byte > PropertyGetterStrategyBlocklist = new(); private static readonly ConcurrentDictionary< CapabilityKey, Action > PropertySetters = new(); private static readonly ConcurrentDictionary< CapabilityKey, byte > PropertySetterStrategyBlocklist = new(); private static readonly ConcurrentDictionary< CapabilityKey, Func > IndexerGetters = new(); private static readonly ConcurrentDictionary< CapabilityKey, byte > IndexerGetterStrategyBlocklist = new(); private static readonly ConcurrentDictionary< CapabilityKey, Action > IndexerSetters = new(); private static readonly ConcurrentDictionary< CapabilityKey, byte > IndexerSetterStrategyBlocklist = new(); private static readonly ConcurrentDictionary< CapabilityKey<(FieldInfo field, Type instance, Type value)>, Delegate > TypedFieldGetters = new(); private static readonly ConcurrentDictionary< CapabilityKey<(FieldInfo field, Type instance, Type value)>, byte > TypedFieldGetterStrategyBlocklist = new(); private static readonly ConcurrentDictionary< CapabilityKey<(FieldInfo field, Type instance, Type value)>, Delegate > TypedFieldSetters = new(); private static readonly ConcurrentDictionary< CapabilityKey<(FieldInfo field, Type instance, Type value)>, byte > TypedFieldSetterStrategyBlocklist = new(); private static readonly ConcurrentDictionary< CapabilityKey<(FieldInfo field, Type value)>, Delegate > TypedStaticFieldGetters = new(); private static readonly ConcurrentDictionary< CapabilityKey<(FieldInfo field, Type value)>, byte > TypedStaticFieldGetterStrategyBlocklist = new(); private static readonly ConcurrentDictionary< CapabilityKey<(FieldInfo field, Type value)>, Delegate > TypedStaticFieldSetters = new(); private static readonly ConcurrentDictionary< CapabilityKey<(FieldInfo field, Type value)>, byte > TypedStaticFieldSetterStrategyBlocklist = new(); private static readonly ConcurrentDictionary< CapabilityKey, Func > MethodInvokers = new(); private static readonly ConcurrentDictionary< CapabilityKey, byte > MethodInvokerStrategyBlocklist = new(); private static readonly ConcurrentDictionary< CapabilityKey, Func > StaticMethodInvokers = new(); private static readonly ConcurrentDictionary< CapabilityKey, byte > StaticMethodInvokerStrategyBlocklist = new(); private static readonly ConcurrentDictionary< CapabilityKey, Func > Constructors = new(); private static readonly ConcurrentDictionary< CapabilityKey, byte > ConstructorInvokerStrategyBlocklist = new(); private static readonly ConcurrentDictionary< CapabilityKey, Func > ParameterlessConstructors = new(); private static readonly ConcurrentDictionary< CapabilityKey, byte > ParameterlessConstructorStrategyBlocklist = new(); private static readonly ConcurrentDictionary< CapabilityKey<(ConstructorInfo ctor, Type instance)>, Delegate > TypedParameterlessConstructors = new(); private static readonly ConcurrentDictionary< CapabilityKey<(ConstructorInfo ctor, Type instance)>, byte > TypedParameterlessConstructorStrategyBlocklist = new(); private static readonly ConcurrentDictionary< (PropertyInfo property, Type instance, Type value), Delegate > TypedPropertyGetters = new(); private static readonly ConcurrentDictionary< (PropertyInfo property, Type instance, Type value), Delegate > TypedPropertySetters = new(); private static readonly ConcurrentDictionary< (PropertyInfo property, Type value), Delegate > TypedStaticPropertyGetters = new(); private static readonly ConcurrentDictionary< (PropertyInfo property, Type value), Delegate > TypedStaticPropertySetters = new(); private static readonly ConcurrentDictionary TypedStaticInvoker0 = new(); private static readonly ConcurrentDictionary TypedStaticInvoker1 = new(); private static readonly ConcurrentDictionary TypedStaticInvoker2 = new(); private static readonly ConcurrentDictionary TypedStaticInvoker3 = new(); private static readonly ConcurrentDictionary TypedStaticInvoker4 = new(); private static readonly ConcurrentDictionary TypedStaticAction0 = new(); private static readonly ConcurrentDictionary TypedStaticAction1 = new(); private static readonly ConcurrentDictionary TypedStaticAction2 = new(); private static readonly ConcurrentDictionary TypedStaticAction3 = new(); private static readonly ConcurrentDictionary TypedStaticAction4 = new(); private static readonly ConcurrentDictionary< MethodInfo, Delegate > TypedInstanceInvoker0 = new(); private static readonly ConcurrentDictionary< MethodInfo, Delegate > TypedInstanceInvoker1 = new(); private static readonly ConcurrentDictionary< MethodInfo, Delegate > TypedInstanceInvoker2 = new(); private static readonly ConcurrentDictionary< MethodInfo, Delegate > TypedInstanceInvoker3 = new(); private static readonly ConcurrentDictionary< MethodInfo, Delegate > TypedInstanceInvoker4 = new(); private static readonly ConcurrentDictionary< MethodInfo, Delegate > TypedInstanceAction0 = new(); private static readonly ConcurrentDictionary< MethodInfo, Delegate > TypedInstanceAction1 = new(); private static readonly ConcurrentDictionary< MethodInfo, Delegate > TypedInstanceAction2 = new(); private static readonly ConcurrentDictionary< MethodInfo, Delegate > TypedInstanceAction3 = new(); private static readonly ConcurrentDictionary< MethodInfo, Delegate > TypedInstanceAction4 = new(); #else private static readonly Dictionary< CapabilityKey, Func > FieldGetters = new(); private static readonly HashSet> FieldGetterStrategyBlocklist = new(); private static readonly Dictionary< CapabilityKey, Action > FieldSetters = new(); private static readonly HashSet> FieldSetterStrategyBlocklist = new(); private static readonly Dictionary< CapabilityKey, Func > StaticFieldGetters = new(); private static readonly HashSet< CapabilityKey > StaticFieldGetterStrategyBlocklist = new(); private static readonly Dictionary< CapabilityKey, Action > StaticFieldSetters = new(); private static readonly HashSet< CapabilityKey > StaticFieldSetterStrategyBlocklist = new(); private static readonly Dictionary< CapabilityKey, Func > PropertyGetters = new(); private static readonly HashSet< CapabilityKey > PropertyGetterStrategyBlocklist = new(); private static readonly Dictionary< CapabilityKey, Action > PropertySetters = new(); private static readonly HashSet< CapabilityKey > PropertySetterStrategyBlocklist = new(); private static readonly Dictionary< CapabilityKey, Func > IndexerGetters = new(); private static readonly Dictionary< CapabilityKey, byte > IndexerGetterStrategyBlocklist = new(); private static readonly Dictionary< CapabilityKey, Action > IndexerSetters = new(); private static readonly Dictionary< CapabilityKey, byte > IndexerSetterStrategyBlocklist = new(); private static readonly Dictionary< CapabilityKey<(FieldInfo field, Type instance, Type value)>, Delegate > TypedFieldGetters = new(); private static readonly HashSet< CapabilityKey<(FieldInfo field, Type instance, Type value)> > TypedFieldGetterStrategyBlocklist = new(); private static readonly Dictionary< CapabilityKey<(FieldInfo field, Type instance, Type value)>, Delegate > TypedFieldSetters = new(); private static readonly HashSet< CapabilityKey<(FieldInfo field, Type instance, Type value)> > TypedFieldSetterStrategyBlocklist = new(); private static readonly Dictionary< CapabilityKey<(FieldInfo field, Type value)>, Delegate > TypedStaticFieldGetters = new(); private static readonly HashSet< CapabilityKey<(FieldInfo field, Type value)> > TypedStaticFieldGetterStrategyBlocklist = new(); private static readonly Dictionary< CapabilityKey<(FieldInfo field, Type value)>, Delegate > TypedStaticFieldSetters = new(); private static readonly HashSet< CapabilityKey<(FieldInfo field, Type value)> > TypedStaticFieldSetterStrategyBlocklist = new(); private static readonly Dictionary< CapabilityKey, Func > MethodInvokers = new(); private static readonly Dictionary< CapabilityKey, byte > MethodInvokerStrategyBlocklist = new(); private static readonly Dictionary< CapabilityKey, Func > StaticMethodInvokers = new(); private static readonly HashSet< CapabilityKey > StaticMethodInvokerStrategyBlocklist = new(); private static readonly Dictionary< CapabilityKey, Func > Constructors = new(); private static readonly HashSet< CapabilityKey > ConstructorInvokerStrategyBlocklist = new(); private static readonly Dictionary< CapabilityKey, Func > ParameterlessConstructors = new(); private static readonly Dictionary< CapabilityKey<(ConstructorInfo ctor, Type instance)>, Delegate > TypedParameterlessConstructors = new(); private static readonly HashSet< CapabilityKey<(ConstructorInfo ctor, Type instance)> > TypedParameterlessConstructorStrategyBlocklist = new(); private static readonly HashSet< CapabilityKey > ParameterlessConstructorStrategyBlocklist = new(); private static readonly Dictionary< (PropertyInfo property, Type instance, Type value), Delegate > TypedPropertyGetters = new(); private static readonly Dictionary< (PropertyInfo property, Type instance, Type value), Delegate > TypedPropertySetters = new(); private static readonly Dictionary< (PropertyInfo property, Type value), Delegate > TypedStaticPropertyGetters = new(); private static readonly Dictionary< (PropertyInfo property, Type value), Delegate > TypedStaticPropertySetters = new(); private static readonly Dictionary TypedStaticInvoker0 = new(); private static readonly Dictionary TypedStaticInvoker1 = new(); private static readonly Dictionary TypedStaticInvoker2 = new(); private static readonly Dictionary TypedStaticInvoker3 = new(); private static readonly Dictionary TypedStaticInvoker4 = new(); private static readonly Dictionary TypedStaticAction0 = new(); private static readonly Dictionary TypedStaticAction1 = new(); private static readonly Dictionary TypedStaticAction2 = new(); private static readonly Dictionary TypedStaticAction3 = new(); private static readonly Dictionary TypedStaticAction4 = new(); private static readonly Dictionary TypedInstanceInvoker0 = new(); private static readonly Dictionary TypedInstanceInvoker1 = new(); private static readonly Dictionary TypedInstanceInvoker2 = new(); private static readonly Dictionary TypedInstanceInvoker3 = new(); private static readonly Dictionary TypedInstanceInvoker4 = new(); private static readonly Dictionary TypedInstanceAction0 = new(); private static readonly Dictionary TypedInstanceAction1 = new(); private static readonly Dictionary TypedInstanceAction2 = new(); private static readonly Dictionary TypedInstanceAction3 = new(); private static readonly Dictionary TypedInstanceAction4 = new(); #endif private static bool SupportsExpressions => ExpressionsEnabled; private static bool SupportsDynamicIl => DynamicIlEnabled; public static Func GetFieldGetter(FieldInfo field) { if (field == null) { throw new ArgumentNullException(nameof(field)); } // Prefer Dynamic IL over Expressions because Expression.Compile() // creates closure-based delegates that are slower than direct IL emission. if ( TryGetOrCreateFieldGetter( field, ReflectionDelegateStrategy.DynamicIl, out Func getter ) ) { return getter; } if ( TryGetOrCreateFieldGetter( field, ReflectionDelegateStrategy.Expressions, out getter ) ) { return getter; } return GetOrCreateReflectionFieldGetter(field); } public static bool IsFieldGetterCached(FieldInfo field) { if (field == null) { return false; } CapabilityKey expressionsKey = new( field, ReflectionDelegateStrategy.Expressions ); CapabilityKey dynamicIlKey = new( field, ReflectionDelegateStrategy.DynamicIl ); CapabilityKey reflectionKey = new( field, ReflectionDelegateStrategy.Reflection ); return FieldGetters.ContainsKey(expressionsKey) || FieldGetters.ContainsKey(dynamicIlKey) || FieldGetters.ContainsKey(reflectionKey); } public static Func GetStaticFieldGetter(FieldInfo field) { if (field == null) { throw new ArgumentNullException(nameof(field)); } if (!field.IsStatic) { throw new ArgumentException("Field must be static", nameof(field)); } // Static field access: prefer Dynamic IL over Expressions because // Expression.Compile() has inherent closure overhead for static field access // that makes it slower than direct IL emission or even raw reflection. if ( TryGetOrCreateStaticFieldGetter( field, ReflectionDelegateStrategy.DynamicIl, out Func getter ) ) { return getter; } if ( TryGetOrCreateStaticFieldGetter( field, ReflectionDelegateStrategy.Expressions, out getter ) ) { return getter; } return GetOrCreateReflectionStaticFieldGetter(field); } public static bool IsStaticFieldGetterCached(FieldInfo field) { if (field == null) { return false; } CapabilityKey expressionsKey = new( field, ReflectionDelegateStrategy.Expressions ); CapabilityKey dynamicIlKey = new( field, ReflectionDelegateStrategy.DynamicIl ); CapabilityKey reflectionKey = new( field, ReflectionDelegateStrategy.Reflection ); return StaticFieldGetters.ContainsKey(expressionsKey) || StaticFieldGetters.ContainsKey(dynamicIlKey) || StaticFieldGetters.ContainsKey(reflectionKey); } public static Action GetFieldSetter(FieldInfo field) { if (field == null) { throw new ArgumentNullException(nameof(field)); } // Prefer Dynamic IL over Expressions because Expression.Compile() // creates closure-based delegates that are slower than direct IL emission. if ( TryGetOrCreateFieldSetter( field, ReflectionDelegateStrategy.DynamicIl, out Action setter ) ) { return setter; } if ( TryGetOrCreateFieldSetter( field, ReflectionDelegateStrategy.Expressions, out setter ) ) { return setter; } return GetOrCreateReflectionFieldSetter(field); } public static bool IsFieldSetterCached(FieldInfo field) { if (field == null) { return false; } CapabilityKey expressionsKey = new( field, ReflectionDelegateStrategy.Expressions ); CapabilityKey dynamicIlKey = new( field, ReflectionDelegateStrategy.DynamicIl ); CapabilityKey reflectionKey = new( field, ReflectionDelegateStrategy.Reflection ); return FieldSetters.ContainsKey(expressionsKey) || FieldSetters.ContainsKey(dynamicIlKey) || FieldSetters.ContainsKey(reflectionKey); } public static Action GetStaticFieldSetter(FieldInfo field) { if (field == null) { throw new ArgumentNullException(nameof(field)); } if (!field.IsStatic) { throw new ArgumentException("Field must be static", nameof(field)); } // Static field access: prefer Dynamic IL over Expressions because // Expression.Compile() has inherent closure overhead for static field access. if ( TryGetOrCreateStaticFieldSetter( field, ReflectionDelegateStrategy.DynamicIl, out Action setter ) ) { return setter; } if ( TryGetOrCreateStaticFieldSetter( field, ReflectionDelegateStrategy.Expressions, out setter ) ) { return setter; } return GetOrCreateReflectionStaticFieldSetter(field); } public static bool IsStaticFieldSetterCached(FieldInfo field) { if (field == null) { return false; } CapabilityKey expressionsKey = new( field, ReflectionDelegateStrategy.Expressions ); CapabilityKey dynamicIlKey = new( field, ReflectionDelegateStrategy.DynamicIl ); CapabilityKey reflectionKey = new( field, ReflectionDelegateStrategy.Reflection ); return StaticFieldSetters.ContainsKey(expressionsKey) || StaticFieldSetters.ContainsKey(dynamicIlKey) || StaticFieldSetters.ContainsKey(reflectionKey); } public static Func GetPropertyGetter(PropertyInfo property) { if (property == null) { throw new ArgumentNullException(nameof(property)); } if ( TryGetOrCreatePropertyGetter( property, ReflectionDelegateStrategy.Expressions, out Func getter ) ) { return getter; } if ( TryGetOrCreatePropertyGetter( property, ReflectionDelegateStrategy.DynamicIl, out getter ) ) { return getter; } return GetOrCreateReflectionPropertyGetter(property); } public static Func GetStaticPropertyGetter(PropertyInfo property) { return GetPropertyGetter(property); } public static Action GetPropertySetter(PropertyInfo property) { if (property == null) { throw new ArgumentNullException(nameof(property)); } if ( TryGetOrCreatePropertySetter( property, ReflectionDelegateStrategy.Expressions, out Action setter ) ) { return setter; } if ( TryGetOrCreatePropertySetter( property, ReflectionDelegateStrategy.DynamicIl, out setter ) ) { return setter; } return GetOrCreateReflectionPropertySetter(property); } public static Func GetMethodInvoker(MethodInfo method) { if (method == null) { throw new ArgumentNullException(nameof(method)); } if (method.IsStatic) { throw new ArgumentException( "Method must be an instance method", nameof(method) ); } if ( TryGetOrCreateMethodInvoker( method, ReflectionDelegateStrategy.Expressions, out Func invoker ) ) { return invoker; } if ( TryGetOrCreateMethodInvoker( method, ReflectionDelegateStrategy.DynamicIl, out invoker ) ) { return invoker; } return GetOrCreateReflectionMethodInvoker(method); } public static Func GetStaticMethodInvoker(MethodInfo method) { if (method == null) { throw new ArgumentNullException(nameof(method)); } if (!method.IsStatic) { throw new ArgumentException("Method must be static", nameof(method)); } if ( TryGetOrCreateStaticMethodInvoker( method, ReflectionDelegateStrategy.Expressions, out Func invoker ) ) { return invoker; } if ( TryGetOrCreateStaticMethodInvoker( method, ReflectionDelegateStrategy.DynamicIl, out invoker ) ) { return invoker; } return GetOrCreateReflectionStaticMethodInvoker(method); } public static Func GetConstructorInvoker(ConstructorInfo ctor) { if (ctor == null) { throw new ArgumentNullException(nameof(ctor)); } if ( TryGetOrCreateConstructorInvoker( ctor, ReflectionDelegateStrategy.Expressions, out Func invoker ) ) { return invoker; } if ( TryGetOrCreateConstructorInvoker( ctor, ReflectionDelegateStrategy.DynamicIl, out invoker ) ) { return invoker; } return GetOrCreateReflectionConstructorInvoker(ctor); } public static Func GetParameterlessConstructor(ConstructorInfo ctor) { if (ctor == null) { throw new ArgumentNullException(nameof(ctor)); } if ( TryGetOrCreateParameterlessConstructor( ctor, ReflectionDelegateStrategy.Expressions, out Func creator ) ) { return creator; } if ( TryGetOrCreateParameterlessConstructor( ctor, ReflectionDelegateStrategy.DynamicIl, out creator ) ) { return creator; } return GetOrCreateReflectionParameterlessConstructor(ctor); } public static Func GetParameterlessConstructorTyped(ConstructorInfo ctor) { if (ctor == null) { throw new ArgumentNullException(nameof(ctor)); } if ( TryGetOrCreateTypedParameterlessConstructor( ctor, typeof(T), ReflectionDelegateStrategy.Expressions, out Func creator ) ) { return creator; } if ( TryGetOrCreateTypedParameterlessConstructor( ctor, typeof(T), ReflectionDelegateStrategy.DynamicIl, out creator ) ) { return creator; } return GetOrCreateReflectionTypedParameterlessConstructor(ctor); } public static Func GetIndexerGetter(PropertyInfo property) { if (property == null) { throw new ArgumentNullException(nameof(property)); } if ( TryGetOrCreateIndexerGetter( property, ReflectionDelegateStrategy.Expressions, out Func getter ) ) { return getter; } if ( TryGetOrCreateIndexerGetter( property, ReflectionDelegateStrategy.DynamicIl, out getter ) ) { return getter; } return GetOrCreateReflectionIndexerGetter(property); } public static Action GetIndexerSetter(PropertyInfo property) { if (property == null) { throw new ArgumentNullException(nameof(property)); } if ( TryGetOrCreateIndexerSetter( property, ReflectionDelegateStrategy.Expressions, out Action setter ) ) { return setter; } if ( TryGetOrCreateIndexerSetter( property, ReflectionDelegateStrategy.DynamicIl, out setter ) ) { return setter; } return GetOrCreateReflectionIndexerSetter(property); } public static Func GetFieldGetterTyped( FieldInfo field ) { if (field == null) { throw new ArgumentNullException(nameof(field)); } // Prefer Dynamic IL over Expressions because Expression.Compile() // creates closure-based delegates that are slower than direct IL emission. if ( TryGetOrCreateTypedFieldGetter( field, ReflectionDelegateStrategy.DynamicIl, out Func getter ) ) { return getter; } if ( TryGetOrCreateTypedFieldGetter( field, ReflectionDelegateStrategy.Expressions, out getter ) ) { return getter; } return GetOrCreateReflectionTypedFieldGetter(field); } public static FieldSetter GetFieldSetterTyped( FieldInfo field ) { if (field == null) { throw new ArgumentNullException(nameof(field)); } // Prefer Dynamic IL over Expressions because Expression.Compile() // creates closure-based delegates that are slower than direct IL emission. if ( TryGetOrCreateTypedFieldSetter( field, ReflectionDelegateStrategy.DynamicIl, out FieldSetter setter ) ) { return setter; } if ( TryGetOrCreateTypedFieldSetter( field, ReflectionDelegateStrategy.Expressions, out setter ) ) { return setter; } return GetOrCreateReflectionTypedFieldSetter(field); } public static Func GetStaticFieldGetterTyped(FieldInfo field) { if (field == null) { throw new ArgumentNullException(nameof(field)); } if (!field.IsStatic) { throw new ArgumentException("Field must be static", nameof(field)); } // Static field access: prefer Dynamic IL over Expressions because // Expression.Compile() has inherent closure overhead for static field access. if ( TryGetOrCreateTypedStaticFieldGetter( field, ReflectionDelegateStrategy.DynamicIl, out Func getter ) ) { return getter; } if ( TryGetOrCreateTypedStaticFieldGetter( field, ReflectionDelegateStrategy.Expressions, out getter ) ) { return getter; } return GetOrCreateReflectionTypedStaticFieldGetter(field); } public static Action GetStaticFieldSetterTyped(FieldInfo field) { if (field == null) { throw new ArgumentNullException(nameof(field)); } if (!field.IsStatic) { throw new ArgumentException("Field must be static", nameof(field)); } // Static field access: prefer Dynamic IL over Expressions because // Expression.Compile() has inherent closure overhead for static field access. if ( TryGetOrCreateTypedStaticFieldSetter( field, ReflectionDelegateStrategy.DynamicIl, out Action setter ) ) { return setter; } if ( TryGetOrCreateTypedStaticFieldSetter( field, ReflectionDelegateStrategy.Expressions, out setter ) ) { return setter; } return GetOrCreateReflectionTypedStaticFieldSetter(field); } public static Func GetPropertyGetterTyped( PropertyInfo property ) { if (property == null) { throw new ArgumentNullException(nameof(property)); } (PropertyInfo property, Type, Type) key = ( property, typeof(TInstance), typeof(TValue) ); #if !SINGLE_THREADED return (Func) TypedPropertyGetters.GetOrAdd( key, _ => BuildTypedPropertyGetter(property) ); #else if (!TypedPropertyGetters.TryGetValue(key, out Delegate del)) { del = BuildTypedPropertyGetter(property); TypedPropertyGetters[key] = del; } return (Func)del; #endif } public static Action GetPropertySetterTyped( PropertyInfo property ) { if (property == null) { throw new ArgumentNullException(nameof(property)); } (PropertyInfo property, Type, Type) key = ( property, typeof(TInstance), typeof(TValue) ); #if !SINGLE_THREADED return (Action) TypedPropertySetters.GetOrAdd( key, _ => BuildTypedPropertySetter(property) ); #else if (!TypedPropertySetters.TryGetValue(key, out Delegate del)) { del = BuildTypedPropertySetter(property); TypedPropertySetters[key] = del; } return (Action)del; #endif } public static Func GetStaticPropertyGetterTyped(PropertyInfo property) { if (property == null) { throw new ArgumentNullException(nameof(property)); } (PropertyInfo property, Type) key = (property, typeof(TValue)); #if !SINGLE_THREADED return (Func) TypedStaticPropertyGetters.GetOrAdd( key, _ => BuildTypedStaticPropertyGetter(property) ); #else if (!TypedStaticPropertyGetters.TryGetValue(key, out Delegate del)) { del = BuildTypedStaticPropertyGetter(property); TypedStaticPropertyGetters[key] = del; } return (Func)del; #endif } public static Action GetStaticPropertySetterTyped(PropertyInfo property) { if (property == null) { throw new ArgumentNullException(nameof(property)); } (PropertyInfo property, Type) key = (property, typeof(TValue)); #if !SINGLE_THREADED return (Action) TypedStaticPropertySetters.GetOrAdd( key, _ => BuildTypedStaticPropertySetter(property) ); #else if (!TypedStaticPropertySetters.TryGetValue(key, out Delegate del)) { del = BuildTypedStaticPropertySetter(property); TypedStaticPropertySetters[key] = del; } return (Action)del; #endif } private static Func CreateIndexerGetter( PropertyInfo property, ReflectionDelegateStrategy strategy ) { if (strategy == ReflectionDelegateStrategy.Expressions) { return CreateCompiledIndexerGetter(property); } #if EMIT_DYNAMIC_IL if (strategy == ReflectionDelegateStrategy.DynamicIl) { return BuildIndexerGetterIL(property); } #endif if (strategy == ReflectionDelegateStrategy.Reflection) { return CreateReflectionIndexerGetter(property); } return null; } private static Action CreateIndexerSetter( PropertyInfo property, ReflectionDelegateStrategy strategy ) { if (strategy == ReflectionDelegateStrategy.Expressions) { return CreateCompiledIndexerSetter(property); } #if EMIT_DYNAMIC_IL if (strategy == ReflectionDelegateStrategy.DynamicIl) { return BuildIndexerSetterIL(property); } #endif if (strategy == ReflectionDelegateStrategy.Reflection) { return CreateReflectionIndexerSetter(property); } return null; } private static Func CreateReflectionIndexerGetter( PropertyInfo property ) { ParameterInfo[] indices = property.GetIndexParameters(); int indexCount = indices.Length; return (instance, indexArgs) => { ValidateIndexArguments(indexArgs, indices, indexCount); return property.GetValue(instance, indexArgs); }; } private static Action CreateReflectionIndexerSetter( PropertyInfo property ) { ParameterInfo[] indices = property.GetIndexParameters(); int indexCount = indices.Length; return (instance, value, indexArgs) => { ValidateIndexArguments(indexArgs, indices, indexCount); property.SetValue(instance, value, indexArgs); }; } private static void ValidateIndexArguments( object[] indexArgs, ParameterInfo[] indices, int indexCount ) { if (indexArgs == null || indexArgs.Length != indexCount) { throw new IndexOutOfRangeException( $"Indexer expects {indexCount} index argument(s); received {(indexArgs == null ? 0 : indexArgs.Length)}." ); } for (int i = 0; i < indexCount; i++) { object arg = indexArgs[i]; Type parameterType = indices[i].ParameterType; if (arg == null) { if ( parameterType.IsValueType && Nullable.GetUnderlyingType(parameterType) == null ) { throw new InvalidCastException( $"Object of type 'null' cannot be converted to type '{parameterType}'." ); } } else if (!parameterType.IsInstanceOfType(arg)) { throw new InvalidCastException( $"Object of type '{arg.GetType()}' cannot be converted to type '{parameterType}'." ); } } } private static Func BuildTypedFieldGetter( FieldInfo field ) { Func getter = null; if (SupportsExpressions) { getter = CreateCompiledTypedFieldGetter(field); } #if EMIT_DYNAMIC_IL if ( getter == null && SupportsDynamicIl && CanInlineReturnConversion(field.FieldType, typeof(TValue)) ) { getter = BuildTypedFieldGetterIL(field); } #endif if (getter != null) { return getter; } if (field.IsStatic) { return _ => (TValue)field.GetValue(null); } if (typeof(TInstance).IsValueType) { return instance => { object boxed = instance; return (TValue)field.GetValue(boxed); }; } return instance => (TValue)field.GetValue(instance); } private static FieldSetter BuildTypedFieldSetter( FieldInfo field ) { FieldSetter setter = null; if (SupportsExpressions) { setter = CreateCompiledTypedFieldSetter(field); } #if EMIT_DYNAMIC_IL if ( setter == null && SupportsDynamicIl && CanInlineAssignment(typeof(TValue), field.FieldType) && (field.IsStatic || typeof(TInstance) == field.DeclaringType) ) { setter = BuildTypedFieldSetterIL(field); } #endif if (setter != null) { return setter; } if (field.IsStatic) { return (ref TInstance _, TValue value) => { field.SetValue(null, value); }; } if (typeof(TInstance).IsValueType) { return (ref TInstance instance, TValue value) => { object boxed = instance; field.SetValue(boxed, value); instance = (TInstance)boxed; }; } return (ref TInstance instance, TValue value) => { field.SetValue(instance, value); }; } private static Func BuildTypedStaticFieldGetter(FieldInfo field) { Func getter = null; if (SupportsExpressions) { getter = CreateCompiledTypedStaticFieldGetter(field); } #if EMIT_DYNAMIC_IL if ( getter == null && SupportsDynamicIl && CanInlineReturnConversion(field.FieldType, typeof(TValue)) ) { getter = BuildTypedStaticFieldGetterIL(field); } #endif return getter ?? (() => (TValue)field.GetValue(null)); } private static Action BuildTypedStaticFieldSetter(FieldInfo field) { Action setter = null; if (SupportsExpressions) { setter = CreateCompiledTypedStaticFieldSetter(field); } #if EMIT_DYNAMIC_IL if ( setter == null && SupportsDynamicIl && CanInlineAssignment(typeof(TValue), field.FieldType) ) { setter = BuildTypedStaticFieldSetterIL(field); } #endif return setter ?? (value => field.SetValue(null, value)); } private static bool TryGetOrCreateFieldGetter( FieldInfo field, ReflectionDelegateStrategy strategy, out Func getter ) { getter = null; if (strategy == ReflectionDelegateStrategy.Expressions && !SupportsExpressions) { return false; } #if EMIT_DYNAMIC_IL if (strategy == ReflectionDelegateStrategy.DynamicIl && !SupportsDynamicIl) { return false; } #else if (strategy == ReflectionDelegateStrategy.DynamicIl) { return false; } #endif CapabilityKey key = new(field, strategy); if (TryGetFieldGetterFromCache(key, out Func cached)) { getter = cached; return true; } if (IsFieldGetterStrategyUnavailable(key)) { return false; } Func candidate = CreateFieldGetter(field, strategy); if (candidate == null) { MarkFieldGetterStrategyUnavailable(key); return false; } Func resolved = AddOrGetFieldGetter(key, candidate); TrackDelegateStrategy(resolved, key); getter = resolved; return true; } private static Func GetOrCreateReflectionFieldGetter(FieldInfo field) { CapabilityKey key = new(field, ReflectionDelegateStrategy.Reflection); if (TryGetFieldGetterFromCache(key, out Func cached)) { return cached; } Func reflectionGetter = CreateReflectionFieldGetter(field); Func resolved = AddOrGetFieldGetter(key, reflectionGetter); TrackDelegateStrategy(resolved, key); return resolved; } private static Func CreateFieldGetter( FieldInfo field, ReflectionDelegateStrategy strategy ) { if (strategy == ReflectionDelegateStrategy.Expressions) { return CreateCompiledFieldGetter(field); } #if EMIT_DYNAMIC_IL if (strategy == ReflectionDelegateStrategy.DynamicIl) { return BuildFieldGetterIL(field); } #endif if (strategy == ReflectionDelegateStrategy.Reflection) { return CreateReflectionFieldGetter(field); } return null; } private static Func CreateReflectionFieldGetter(FieldInfo field) { if (field.IsStatic) { return ignoredInstance => field.GetValue(null); } return instance => field.GetValue(instance); } private static bool TryGetOrCreateFieldSetter( FieldInfo field, ReflectionDelegateStrategy strategy, out Action setter ) { setter = null; if (strategy == ReflectionDelegateStrategy.Expressions && !SupportsExpressions) { return false; } #if EMIT_DYNAMIC_IL if (strategy == ReflectionDelegateStrategy.DynamicIl && !SupportsDynamicIl) { return false; } #else if (strategy == ReflectionDelegateStrategy.DynamicIl) { return false; } #endif CapabilityKey key = new(field, strategy); if (TryGetFieldSetterFromCache(key, out Action cached)) { setter = cached; return true; } if (IsFieldSetterStrategyUnavailable(key)) { return false; } Action candidate = CreateFieldSetter(field, strategy); if (candidate == null) { MarkFieldSetterStrategyUnavailable(key); return false; } Action resolved = AddOrGetFieldSetter(key, candidate); TrackDelegateStrategy(resolved, key); setter = resolved; return true; } private static Action GetOrCreateReflectionFieldSetter(FieldInfo field) { CapabilityKey key = new(field, ReflectionDelegateStrategy.Reflection); if (TryGetFieldSetterFromCache(key, out Action cached)) { return cached; } Action reflectionSetter = CreateReflectionFieldSetter(field); Action resolved = AddOrGetFieldSetter(key, reflectionSetter); TrackDelegateStrategy(resolved, key); return resolved; } private static Action CreateFieldSetter( FieldInfo field, ReflectionDelegateStrategy strategy ) { if (strategy == ReflectionDelegateStrategy.Expressions) { return CreateCompiledFieldSetter(field); } #if EMIT_DYNAMIC_IL if (strategy == ReflectionDelegateStrategy.DynamicIl) { return BuildFieldSetterIL(field); } #endif if (strategy == ReflectionDelegateStrategy.Reflection) { return CreateReflectionFieldSetter(field); } return null; } private static Action CreateReflectionFieldSetter(FieldInfo field) { if (field.IsStatic) { return (_, value) => field.SetValue(null, value); } return (instance, value) => field.SetValue(instance, value); } private static bool TryGetOrCreateStaticFieldGetter( FieldInfo field, ReflectionDelegateStrategy strategy, out Func getter ) { getter = null; if (strategy == ReflectionDelegateStrategy.Expressions && !SupportsExpressions) { return false; } #if EMIT_DYNAMIC_IL if (strategy == ReflectionDelegateStrategy.DynamicIl && !SupportsDynamicIl) { return false; } #else if (strategy == ReflectionDelegateStrategy.DynamicIl) { return false; } #endif CapabilityKey key = new(field, strategy); if (TryGetStaticFieldGetterFromCache(key, out Func cached)) { getter = cached; return true; } if (IsStaticFieldGetterStrategyUnavailable(key)) { return false; } Func candidate = CreateStaticFieldGetter(field, strategy); if (candidate == null) { MarkStaticFieldGetterStrategyUnavailable(key); return false; } Func resolved = AddOrGetStaticFieldGetter(key, candidate); TrackDelegateStrategy(resolved, key); getter = resolved; return true; } private static Func GetOrCreateReflectionStaticFieldGetter(FieldInfo field) { CapabilityKey key = new(field, ReflectionDelegateStrategy.Reflection); if (TryGetStaticFieldGetterFromCache(key, out Func cached)) { return cached; } Func reflectionGetter = CreateReflectionStaticFieldGetter(field); Func resolved = AddOrGetStaticFieldGetter(key, reflectionGetter); TrackDelegateStrategy(resolved, key); return resolved; } private static Func CreateStaticFieldGetter( FieldInfo field, ReflectionDelegateStrategy strategy ) { if (strategy == ReflectionDelegateStrategy.Expressions) { return CreateCompiledStaticFieldGetter(field); } #if EMIT_DYNAMIC_IL if (strategy == ReflectionDelegateStrategy.DynamicIl) { return BuildStaticFieldGetterIL(field); } #endif if (strategy == ReflectionDelegateStrategy.Reflection) { return CreateReflectionStaticFieldGetter(field); } return null; } private static Func CreateReflectionStaticFieldGetter(FieldInfo field) { return () => field.GetValue(null); } private static bool TryGetOrCreateStaticFieldSetter( FieldInfo field, ReflectionDelegateStrategy strategy, out Action setter ) { setter = null; if (strategy == ReflectionDelegateStrategy.Expressions && !SupportsExpressions) { return false; } #if EMIT_DYNAMIC_IL if (strategy == ReflectionDelegateStrategy.DynamicIl && !SupportsDynamicIl) { return false; } #else if (strategy == ReflectionDelegateStrategy.DynamicIl) { return false; } #endif CapabilityKey key = new(field, strategy); if (TryGetStaticFieldSetterFromCache(key, out Action cached)) { setter = cached; return true; } if (IsStaticFieldSetterStrategyUnavailable(key)) { return false; } Action candidate = CreateStaticFieldSetter(field, strategy); if (candidate == null) { MarkStaticFieldSetterStrategyUnavailable(key); return false; } Action resolved = AddOrGetStaticFieldSetter(key, candidate); TrackDelegateStrategy(resolved, key); setter = resolved; return true; } private static Action GetOrCreateReflectionStaticFieldSetter(FieldInfo field) { CapabilityKey key = new(field, ReflectionDelegateStrategy.Reflection); if (TryGetStaticFieldSetterFromCache(key, out Action cached)) { return cached; } Action reflectionSetter = CreateReflectionStaticFieldSetter(field); Action resolved = AddOrGetStaticFieldSetter(key, reflectionSetter); TrackDelegateStrategy(resolved, key); return resolved; } private static Action CreateStaticFieldSetter( FieldInfo field, ReflectionDelegateStrategy strategy ) { if (strategy == ReflectionDelegateStrategy.Expressions) { return CreateCompiledStaticFieldSetter(field); } #if EMIT_DYNAMIC_IL if (strategy == ReflectionDelegateStrategy.DynamicIl) { return BuildStaticFieldSetterIL(field); } #endif if (strategy == ReflectionDelegateStrategy.Reflection) { return CreateReflectionStaticFieldSetter(field); } return null; } private static Action CreateReflectionStaticFieldSetter(FieldInfo field) { return value => field.SetValue(null, value); } private static bool TryGetOrCreateTypedFieldGetter( FieldInfo field, ReflectionDelegateStrategy strategy, out Func getter ) { getter = null; if (strategy == ReflectionDelegateStrategy.Expressions && !SupportsExpressions) { return false; } #if EMIT_DYNAMIC_IL if (strategy == ReflectionDelegateStrategy.DynamicIl && !SupportsDynamicIl) { return false; } #else if (strategy == ReflectionDelegateStrategy.DynamicIl) { return false; } #endif CapabilityKey<(FieldInfo field, Type instance, Type value)> key = new( (field, typeof(TInstance), typeof(TValue)), strategy ); if (TryGetTypedFieldGetterFromCache(key, out Delegate cached)) { getter = (Func)cached; return true; } if (IsTypedFieldGetterStrategyUnavailable(key)) { return false; } Func candidate = CreateTypedFieldGetter( field, strategy ); if (candidate == null) { MarkTypedFieldGetterStrategyUnavailable(key); return false; } Delegate resolved = AddOrGetTypedFieldGetter(key, candidate); TrackDelegateStrategy(resolved, key); getter = (Func)resolved; return true; } private static Func GetOrCreateReflectionTypedFieldGetter< TInstance, TValue >(FieldInfo field) { CapabilityKey<(FieldInfo field, Type instance, Type value)> key = new( (field, typeof(TInstance), typeof(TValue)), ReflectionDelegateStrategy.Reflection ); if (TryGetTypedFieldGetterFromCache(key, out Delegate cached)) { return (Func)cached; } Func reflectionGetter = CreateReflectionTypedFieldGetter< TInstance, TValue >(field); Delegate resolved = AddOrGetTypedFieldGetter(key, reflectionGetter); TrackDelegateStrategy(resolved, key); return (Func)resolved; } private static Func CreateTypedFieldGetter( FieldInfo field, ReflectionDelegateStrategy strategy ) { if (strategy == ReflectionDelegateStrategy.Expressions) { return CreateCompiledTypedFieldGetter(field); } #if EMIT_DYNAMIC_IL if (strategy == ReflectionDelegateStrategy.DynamicIl) { if (!CanInlineReturnConversion(field.FieldType, typeof(TValue))) { return null; } return BuildTypedFieldGetterIL(field); } #endif if (strategy == ReflectionDelegateStrategy.Reflection) { return CreateReflectionTypedFieldGetter(field); } return null; } private static Func CreateReflectionTypedFieldGetter< TInstance, TValue >(FieldInfo field) { if (field.IsStatic) { return _ => (TValue)field.GetValue(null); } if (typeof(TInstance).IsValueType) { return instance => { object boxed = instance; return (TValue)field.GetValue(boxed); }; } return instance => (TValue)field.GetValue(instance); } private static bool TryGetOrCreateTypedFieldSetter( FieldInfo field, ReflectionDelegateStrategy strategy, out FieldSetter setter ) { setter = null; if (strategy == ReflectionDelegateStrategy.Expressions && !SupportsExpressions) { return false; } #if EMIT_DYNAMIC_IL if (strategy == ReflectionDelegateStrategy.DynamicIl && !SupportsDynamicIl) { return false; } #else if (strategy == ReflectionDelegateStrategy.DynamicIl) { return false; } #endif CapabilityKey<(FieldInfo field, Type instance, Type value)> key = new( (field, typeof(TInstance), typeof(TValue)), strategy ); if (TryGetTypedFieldSetterFromCache(key, out Delegate cached)) { setter = (FieldSetter)cached; return true; } if (IsTypedFieldSetterStrategyUnavailable(key)) { return false; } FieldSetter candidate = CreateTypedFieldSetter< TInstance, TValue >(field, strategy); if (candidate == null) { MarkTypedFieldSetterStrategyUnavailable(key); return false; } Delegate resolved = AddOrGetTypedFieldSetter(key, candidate); TrackDelegateStrategy(resolved, key); setter = (FieldSetter)resolved; return true; } private static FieldSetter GetOrCreateReflectionTypedFieldSetter< TInstance, TValue >(FieldInfo field) { CapabilityKey<(FieldInfo field, Type instance, Type value)> key = new( (field, typeof(TInstance), typeof(TValue)), ReflectionDelegateStrategy.Reflection ); if (TryGetTypedFieldSetterFromCache(key, out Delegate cached)) { return (FieldSetter)cached; } FieldSetter reflectionSetter = CreateReflectionTypedFieldSetter< TInstance, TValue >(field); Delegate resolved = AddOrGetTypedFieldSetter(key, reflectionSetter); TrackDelegateStrategy(resolved, key); return (FieldSetter)resolved; } private static FieldSetter CreateTypedFieldSetter( FieldInfo field, ReflectionDelegateStrategy strategy ) { if (strategy == ReflectionDelegateStrategy.Expressions) { return CreateCompiledTypedFieldSetter(field); } #if EMIT_DYNAMIC_IL if (strategy == ReflectionDelegateStrategy.DynamicIl) { if ( !CanInlineAssignment(typeof(TValue), field.FieldType) || (!field.IsStatic && typeof(TInstance) != field.DeclaringType) ) { return null; } return BuildTypedFieldSetterIL(field); } #endif if (strategy == ReflectionDelegateStrategy.Reflection) { return CreateReflectionTypedFieldSetter(field); } return null; } private static FieldSetter CreateReflectionTypedFieldSetter< TInstance, TValue >(FieldInfo field) { if (field.IsStatic) { return (ref TInstance _, TValue value) => { field.SetValue(null, value); }; } if (typeof(TInstance).IsValueType) { return (ref TInstance instance, TValue value) => { object boxed = instance; field.SetValue(boxed, value); instance = (TInstance)boxed; }; } return (ref TInstance instance, TValue value) => { field.SetValue(instance, value); }; } private static bool TryGetOrCreateTypedStaticFieldGetter( FieldInfo field, ReflectionDelegateStrategy strategy, out Func getter ) { getter = null; if (strategy == ReflectionDelegateStrategy.Expressions && !SupportsExpressions) { return false; } #if EMIT_DYNAMIC_IL if (strategy == ReflectionDelegateStrategy.DynamicIl && !SupportsDynamicIl) { return false; } #else if (strategy == ReflectionDelegateStrategy.DynamicIl) { return false; } #endif CapabilityKey<(FieldInfo field, Type value)> key = new( (field, typeof(TValue)), strategy ); if (TryGetTypedStaticFieldGetterFromCache(key, out Delegate cached)) { getter = (Func)cached; return true; } if (IsTypedStaticFieldGetterStrategyUnavailable(key)) { return false; } Func candidate = CreateTypedStaticFieldGetter(field, strategy); if (candidate == null) { MarkTypedStaticFieldGetterStrategyUnavailable(key); return false; } Delegate resolved = AddOrGetTypedStaticFieldGetter(key, candidate); TrackDelegateStrategy(resolved, key); getter = (Func)resolved; return true; } private static Func GetOrCreateReflectionTypedStaticFieldGetter( FieldInfo field ) { CapabilityKey<(FieldInfo field, Type value)> key = new( (field, typeof(TValue)), ReflectionDelegateStrategy.Reflection ); if (TryGetTypedStaticFieldGetterFromCache(key, out Delegate cached)) { return (Func)cached; } Func reflectionGetter = CreateReflectionTypedStaticFieldGetter( field ); Delegate resolved = AddOrGetTypedStaticFieldGetter(key, reflectionGetter); TrackDelegateStrategy(resolved, key); return (Func)resolved; } private static Func CreateTypedStaticFieldGetter( FieldInfo field, ReflectionDelegateStrategy strategy ) { if (strategy == ReflectionDelegateStrategy.Expressions) { return CreateCompiledTypedStaticFieldGetter(field); } #if EMIT_DYNAMIC_IL if (strategy == ReflectionDelegateStrategy.DynamicIl) { if (!CanInlineReturnConversion(field.FieldType, typeof(TValue))) { return null; } return BuildTypedStaticFieldGetterIL(field); } #endif if (strategy == ReflectionDelegateStrategy.Reflection) { return CreateReflectionTypedStaticFieldGetter(field); } return null; } private static Func CreateReflectionTypedStaticFieldGetter( FieldInfo field ) { return () => (TValue)field.GetValue(null); } private static bool TryGetOrCreateTypedStaticFieldSetter( FieldInfo field, ReflectionDelegateStrategy strategy, out Action setter ) { setter = null; if (strategy == ReflectionDelegateStrategy.Expressions && !SupportsExpressions) { return false; } #if EMIT_DYNAMIC_IL if (strategy == ReflectionDelegateStrategy.DynamicIl && !SupportsDynamicIl) { return false; } #else if (strategy == ReflectionDelegateStrategy.DynamicIl) { return false; } #endif CapabilityKey<(FieldInfo field, Type value)> key = new( (field, typeof(TValue)), strategy ); if (TryGetTypedStaticFieldSetterFromCache(key, out Delegate cached)) { setter = (Action)cached; return true; } if (IsTypedStaticFieldSetterStrategyUnavailable(key)) { return false; } Action candidate = CreateTypedStaticFieldSetter(field, strategy); if (candidate == null) { MarkTypedStaticFieldSetterStrategyUnavailable(key); return false; } Delegate resolved = AddOrGetTypedStaticFieldSetter(key, candidate); TrackDelegateStrategy(resolved, key); setter = (Action)resolved; return true; } private static Action GetOrCreateReflectionTypedStaticFieldSetter( FieldInfo field ) { CapabilityKey<(FieldInfo field, Type value)> key = new( (field, typeof(TValue)), ReflectionDelegateStrategy.Reflection ); if (TryGetTypedStaticFieldSetterFromCache(key, out Delegate cached)) { return (Action)cached; } Action reflectionSetter = CreateReflectionTypedStaticFieldSetter( field ); Delegate resolved = AddOrGetTypedStaticFieldSetter(key, reflectionSetter); TrackDelegateStrategy(resolved, key); return (Action)resolved; } private static Action CreateTypedStaticFieldSetter( FieldInfo field, ReflectionDelegateStrategy strategy ) { if (strategy == ReflectionDelegateStrategy.Expressions) { return CreateCompiledTypedStaticFieldSetter(field); } #if EMIT_DYNAMIC_IL if (strategy == ReflectionDelegateStrategy.DynamicIl) { if (!CanInlineAssignment(typeof(TValue), field.FieldType)) { return null; } return BuildTypedStaticFieldSetterIL(field); } #endif if (strategy == ReflectionDelegateStrategy.Reflection) { return CreateReflectionTypedStaticFieldSetter(field); } return null; } private static Action CreateReflectionTypedStaticFieldSetter( FieldInfo field ) { return value => field.SetValue(null, value); } private static bool TryGetOrCreatePropertyGetter( PropertyInfo property, ReflectionDelegateStrategy strategy, out Func getter ) { getter = null; if (strategy == ReflectionDelegateStrategy.Expressions && !SupportsExpressions) { return false; } #if EMIT_DYNAMIC_IL if (strategy == ReflectionDelegateStrategy.DynamicIl && !SupportsDynamicIl) { return false; } #else if (strategy == ReflectionDelegateStrategy.DynamicIl) { return false; } #endif CapabilityKey key = new(property, strategy); if (TryGetPropertyGetterFromCache(key, out Func cached)) { getter = cached; return true; } if (IsPropertyGetterStrategyUnavailable(key)) { return false; } Func candidate = CreatePropertyGetter(property, strategy); if (candidate == null) { MarkPropertyGetterStrategyUnavailable(key); return false; } Func resolved = AddOrGetPropertyGetter(key, candidate); TrackDelegateStrategy(resolved, key); getter = resolved; return true; } private static Func GetOrCreateReflectionPropertyGetter( PropertyInfo property ) { CapabilityKey key = new( property, ReflectionDelegateStrategy.Reflection ); if (TryGetPropertyGetterFromCache(key, out Func cached)) { return cached; } Func reflectionGetter = CreateReflectionPropertyGetter(property); Func resolved = AddOrGetPropertyGetter(key, reflectionGetter); TrackDelegateStrategy(resolved, key); return resolved; } private static bool TryGetOrCreatePropertySetter( PropertyInfo property, ReflectionDelegateStrategy strategy, out Action setter ) { setter = null; if (strategy == ReflectionDelegateStrategy.Expressions && !SupportsExpressions) { return false; } #if EMIT_DYNAMIC_IL if (strategy == ReflectionDelegateStrategy.DynamicIl && !SupportsDynamicIl) { return false; } #else if (strategy == ReflectionDelegateStrategy.DynamicIl) { return false; } #endif CapabilityKey key = new(property, strategy); if (TryGetPropertySetterFromCache(key, out Action cached)) { setter = cached; return true; } if (IsPropertySetterStrategyUnavailable(key)) { return false; } Action candidate = CreatePropertySetter(property, strategy); if (candidate == null) { MarkPropertySetterStrategyUnavailable(key); return false; } Action resolved = AddOrGetPropertySetter(key, candidate); TrackDelegateStrategy(resolved, key); setter = resolved; return true; } private static bool TryGetOrCreateIndexerGetter( PropertyInfo property, ReflectionDelegateStrategy strategy, out Func getter ) { getter = null; if (strategy == ReflectionDelegateStrategy.Expressions && !SupportsExpressions) { return false; } #if EMIT_DYNAMIC_IL if (strategy == ReflectionDelegateStrategy.DynamicIl && !SupportsDynamicIl) { return false; } #else if (strategy == ReflectionDelegateStrategy.DynamicIl) { return false; } #endif CapabilityKey key = new(property, strategy); if (TryGetIndexerGetterFromCache(key, out Func cached)) { getter = cached; return true; } if (IsIndexerGetterStrategyUnavailable(key)) { return false; } Func candidate = CreateIndexerGetter(property, strategy); if (candidate == null) { MarkIndexerGetterStrategyUnavailable(key); return false; } Func resolved = AddOrGetIndexerGetter(key, candidate); TrackDelegateStrategy(resolved, key); getter = resolved; return true; } private static Func GetOrCreateReflectionIndexerGetter( PropertyInfo property ) { CapabilityKey key = new( property, ReflectionDelegateStrategy.Reflection ); if (TryGetIndexerGetterFromCache(key, out Func cached)) { return cached; } Func reflectionGetter = CreateReflectionIndexerGetter( property ); Func resolved = AddOrGetIndexerGetter( key, reflectionGetter ); TrackDelegateStrategy(resolved, key); return resolved; } private static bool TryGetOrCreateIndexerSetter( PropertyInfo property, ReflectionDelegateStrategy strategy, out Action setter ) { setter = null; if (strategy == ReflectionDelegateStrategy.Expressions && !SupportsExpressions) { return false; } #if EMIT_DYNAMIC_IL if (strategy == ReflectionDelegateStrategy.DynamicIl && !SupportsDynamicIl) { return false; } #else if (strategy == ReflectionDelegateStrategy.DynamicIl) { return false; } #endif CapabilityKey key = new(property, strategy); if (TryGetIndexerSetterFromCache(key, out Action cached)) { setter = cached; return true; } if (IsIndexerSetterStrategyUnavailable(key)) { return false; } Action candidate = CreateIndexerSetter( property, strategy ); if (candidate == null) { MarkIndexerSetterStrategyUnavailable(key); return false; } Action resolved = AddOrGetIndexerSetter(key, candidate); TrackDelegateStrategy(resolved, key); setter = resolved; return true; } private static Action GetOrCreateReflectionIndexerSetter( PropertyInfo property ) { CapabilityKey key = new( property, ReflectionDelegateStrategy.Reflection ); if (TryGetIndexerSetterFromCache(key, out Action cached)) { return cached; } Action reflectionSetter = CreateReflectionIndexerSetter( property ); Action resolved = AddOrGetIndexerSetter( key, reflectionSetter ); TrackDelegateStrategy(resolved, key); return resolved; } private static Action GetOrCreateReflectionPropertySetter( PropertyInfo property ) { CapabilityKey key = new( property, ReflectionDelegateStrategy.Reflection ); if (TryGetPropertySetterFromCache(key, out Action cached)) { return cached; } Action reflectionSetter = CreateReflectionPropertySetter(property); Action resolved = AddOrGetPropertySetter(key, reflectionSetter); TrackDelegateStrategy(resolved, key); return resolved; } private static bool TryGetOrCreateConstructorInvoker( ConstructorInfo ctor, ReflectionDelegateStrategy strategy, out Func invoker ) { invoker = null; if (strategy == ReflectionDelegateStrategy.Expressions && !SupportsExpressions) { return false; } #if EMIT_DYNAMIC_IL if (strategy == ReflectionDelegateStrategy.DynamicIl && !SupportsDynamicIl) { return false; } #else if (strategy == ReflectionDelegateStrategy.DynamicIl) { return false; } #endif CapabilityKey key = new(ctor, strategy); if (TryGetConstructorInvokerFromCache(key, out Func cached)) { invoker = cached; return true; } if (IsConstructorInvokerStrategyUnavailable(key)) { return false; } Func candidate = CreateConstructorInvoker(ctor, strategy); if (candidate == null) { MarkConstructorInvokerStrategyUnavailable(key); return false; } Func resolved = AddOrGetConstructorInvoker(key, candidate); TrackDelegateStrategy(resolved, key); invoker = resolved; return true; } private static Func GetOrCreateReflectionConstructorInvoker( ConstructorInfo ctor ) { CapabilityKey key = new( ctor, ReflectionDelegateStrategy.Reflection ); if (TryGetConstructorInvokerFromCache(key, out Func cached)) { return cached; } Func reflectionInvoker = CreateReflectionConstructorInvoker(ctor); Func resolved = AddOrGetConstructorInvoker( key, reflectionInvoker ); TrackDelegateStrategy(resolved, key); return resolved; } private static bool TryGetOrCreateParameterlessConstructor( ConstructorInfo ctor, ReflectionDelegateStrategy strategy, out Func creator ) { creator = null; if (strategy == ReflectionDelegateStrategy.Expressions && !SupportsExpressions) { return false; } #if EMIT_DYNAMIC_IL if (strategy == ReflectionDelegateStrategy.DynamicIl && !SupportsDynamicIl) { return false; } #else if (strategy == ReflectionDelegateStrategy.DynamicIl) { return false; } #endif CapabilityKey key = new(ctor, strategy); if (TryGetParameterlessConstructorFromCache(key, out Func cached)) { creator = cached; return true; } if (IsParameterlessConstructorStrategyUnavailable(key)) { return false; } Func candidate = CreateParameterlessConstructor(ctor, strategy); if (candidate == null) { MarkParameterlessConstructorStrategyUnavailable(key); return false; } Func resolved = AddOrGetParameterlessConstructor(key, candidate); TrackDelegateStrategy(resolved, key); creator = resolved; return true; } private static Func GetOrCreateReflectionParameterlessConstructor( ConstructorInfo ctor ) { CapabilityKey key = new( ctor, ReflectionDelegateStrategy.Reflection ); if (TryGetParameterlessConstructorFromCache(key, out Func cached)) { return cached; } Func reflectionCreator = () => ctor.Invoke(null); Func resolved = AddOrGetParameterlessConstructor(key, reflectionCreator); TrackDelegateStrategy(resolved, key); return resolved; } private static bool TryGetOrCreateTypedParameterlessConstructor( ConstructorInfo ctor, Type instanceType, ReflectionDelegateStrategy strategy, out Func creator ) { creator = null; if (strategy == ReflectionDelegateStrategy.Expressions && !SupportsExpressions) { return false; } #if EMIT_DYNAMIC_IL if (strategy == ReflectionDelegateStrategy.DynamicIl && !SupportsDynamicIl) { return false; } #else if (strategy == ReflectionDelegateStrategy.DynamicIl) { return false; } #endif CapabilityKey<(ConstructorInfo ctor, Type instance)> key = new( (ctor, instanceType), strategy ); if (TryGetTypedParameterlessConstructorFromCache(key, out Delegate cached)) { creator = (Func)cached; return true; } if (IsTypedParameterlessConstructorStrategyUnavailable(key)) { return false; } Func candidate = CreateTypedParameterlessConstructor(ctor, strategy); if (candidate == null) { MarkTypedParameterlessConstructorStrategyUnavailable(key); return false; } Delegate resolved = AddOrGetTypedParameterlessConstructor(key, candidate); TrackDelegateStrategy(resolved, key); creator = (Func)resolved; return true; } private static Func GetOrCreateReflectionTypedParameterlessConstructor( ConstructorInfo ctor ) { CapabilityKey<(ConstructorInfo ctor, Type instance)> key = new( (ctor, typeof(T)), ReflectionDelegateStrategy.Reflection ); if (TryGetTypedParameterlessConstructorFromCache(key, out Delegate cached)) { return (Func)cached; } Func reflectionCreator = () => (T)ctor.Invoke(null); Delegate resolved = AddOrGetTypedParameterlessConstructor(key, reflectionCreator); TrackDelegateStrategy(resolved, key); return (Func)resolved; } #if !SINGLE_THREADED private static bool TryGetFieldGetterFromCache( CapabilityKey key, out Func getter ) { return FieldGetters.TryGetValue(key, out getter); } private static Func AddOrGetFieldGetter( CapabilityKey key, Func getter ) { return FieldGetters.GetOrAdd(key, getter); } private static bool IsFieldGetterStrategyUnavailable(CapabilityKey key) { return FieldGetterStrategyBlocklist.ContainsKey(key); } private static void MarkFieldGetterStrategyUnavailable(CapabilityKey key) { FieldGetterStrategyBlocklist.TryAdd(key, StrategyUnavailableSentinel); } private static bool TryGetFieldSetterFromCache( CapabilityKey key, out Action setter ) { return FieldSetters.TryGetValue(key, out setter); } private static Action AddOrGetFieldSetter( CapabilityKey key, Action setter ) { return FieldSetters.GetOrAdd(key, setter); } private static bool IsFieldSetterStrategyUnavailable(CapabilityKey key) { return FieldSetterStrategyBlocklist.ContainsKey(key); } private static void MarkFieldSetterStrategyUnavailable(CapabilityKey key) { FieldSetterStrategyBlocklist.TryAdd(key, StrategyUnavailableSentinel); } private static bool TryGetStaticFieldGetterFromCache( CapabilityKey key, out Func getter ) { return StaticFieldGetters.TryGetValue(key, out getter); } private static Func AddOrGetStaticFieldGetter( CapabilityKey key, Func getter ) { return StaticFieldGetters.GetOrAdd(key, getter); } private static bool IsStaticFieldGetterStrategyUnavailable(CapabilityKey key) { return StaticFieldGetterStrategyBlocklist.ContainsKey(key); } private static void MarkStaticFieldGetterStrategyUnavailable( CapabilityKey key ) { StaticFieldGetterStrategyBlocklist.TryAdd(key, StrategyUnavailableSentinel); } private static bool TryGetStaticFieldSetterFromCache( CapabilityKey key, out Action setter ) { return StaticFieldSetters.TryGetValue(key, out setter); } private static Action AddOrGetStaticFieldSetter( CapabilityKey key, Action setter ) { return StaticFieldSetters.GetOrAdd(key, setter); } private static bool IsStaticFieldSetterStrategyUnavailable(CapabilityKey key) { return StaticFieldSetterStrategyBlocklist.ContainsKey(key); } private static void MarkStaticFieldSetterStrategyUnavailable( CapabilityKey key ) { StaticFieldSetterStrategyBlocklist.TryAdd(key, StrategyUnavailableSentinel); } private static bool TryGetPropertyGetterFromCache( CapabilityKey key, out Func getter ) { return PropertyGetters.TryGetValue(key, out getter); } private static Func AddOrGetPropertyGetter( CapabilityKey key, Func getter ) { return PropertyGetters.GetOrAdd(key, getter); } private static bool IsPropertyGetterStrategyUnavailable(CapabilityKey key) { return PropertyGetterStrategyBlocklist.ContainsKey(key); } private static void MarkPropertyGetterStrategyUnavailable( CapabilityKey key ) { PropertyGetterStrategyBlocklist.TryAdd(key, StrategyUnavailableSentinel); } private static bool TryGetPropertySetterFromCache( CapabilityKey key, out Action setter ) { return PropertySetters.TryGetValue(key, out setter); } private static Action AddOrGetPropertySetter( CapabilityKey key, Action setter ) { return PropertySetters.GetOrAdd(key, setter); } private static bool IsPropertySetterStrategyUnavailable(CapabilityKey key) { return PropertySetterStrategyBlocklist.ContainsKey(key); } private static void MarkPropertySetterStrategyUnavailable( CapabilityKey key ) { PropertySetterStrategyBlocklist.TryAdd(key, StrategyUnavailableSentinel); } private static bool TryGetIndexerGetterFromCache( CapabilityKey key, out Func getter ) { return IndexerGetters.TryGetValue(key, out getter); } private static Func AddOrGetIndexerGetter( CapabilityKey key, Func getter ) { return IndexerGetters.GetOrAdd(key, getter); } private static bool IsIndexerGetterStrategyUnavailable(CapabilityKey key) { return IndexerGetterStrategyBlocklist.ContainsKey(key); } private static void MarkIndexerGetterStrategyUnavailable( CapabilityKey key ) { IndexerGetterStrategyBlocklist.TryAdd(key, StrategyUnavailableSentinel); } private static bool TryGetIndexerSetterFromCache( CapabilityKey key, out Action setter ) { return IndexerSetters.TryGetValue(key, out setter); } private static Action AddOrGetIndexerSetter( CapabilityKey key, Action setter ) { return IndexerSetters.GetOrAdd(key, setter); } private static bool IsIndexerSetterStrategyUnavailable(CapabilityKey key) { return IndexerSetterStrategyBlocklist.ContainsKey(key); } private static void MarkIndexerSetterStrategyUnavailable( CapabilityKey key ) { IndexerSetterStrategyBlocklist.TryAdd(key, StrategyUnavailableSentinel); } private static bool TryGetMethodInvokerFromCache( CapabilityKey key, out Func invoker ) { return MethodInvokers.TryGetValue(key, out invoker); } private static Func AddOrGetMethodInvoker( CapabilityKey key, Func invoker ) { return MethodInvokers.GetOrAdd(key, invoker); } private static bool IsMethodInvokerStrategyUnavailable(CapabilityKey key) { return MethodInvokerStrategyBlocklist.ContainsKey(key); } private static void MarkMethodInvokerStrategyUnavailable(CapabilityKey key) { MethodInvokerStrategyBlocklist.TryAdd(key, StrategyUnavailableSentinel); } private static bool TryGetStaticMethodInvokerFromCache( CapabilityKey key, out Func invoker ) { return StaticMethodInvokers.TryGetValue(key, out invoker); } private static Func AddOrGetStaticMethodInvoker( CapabilityKey key, Func invoker ) { return StaticMethodInvokers.GetOrAdd(key, invoker); } private static bool IsStaticMethodInvokerStrategyUnavailable( CapabilityKey key ) { return StaticMethodInvokerStrategyBlocklist.ContainsKey(key); } private static void MarkStaticMethodInvokerStrategyUnavailable( CapabilityKey key ) { StaticMethodInvokerStrategyBlocklist.TryAdd(key, StrategyUnavailableSentinel); } private static bool TryGetConstructorInvokerFromCache( CapabilityKey key, out Func invoker ) { return Constructors.TryGetValue(key, out invoker); } private static Func AddOrGetConstructorInvoker( CapabilityKey key, Func invoker ) { return Constructors.GetOrAdd(key, invoker); } private static bool IsConstructorInvokerStrategyUnavailable( CapabilityKey key ) { return ConstructorInvokerStrategyBlocklist.ContainsKey(key); } private static void MarkConstructorInvokerStrategyUnavailable( CapabilityKey key ) { ConstructorInvokerStrategyBlocklist.TryAdd(key, StrategyUnavailableSentinel); } private static bool TryGetParameterlessConstructorFromCache( CapabilityKey key, out Func creator ) { return ParameterlessConstructors.TryGetValue(key, out creator); } private static Func AddOrGetParameterlessConstructor( CapabilityKey key, Func creator ) { return ParameterlessConstructors.GetOrAdd(key, creator); } private static bool IsParameterlessConstructorStrategyUnavailable( CapabilityKey key ) { return ParameterlessConstructorStrategyBlocklist.ContainsKey(key); } private static void MarkParameterlessConstructorStrategyUnavailable( CapabilityKey key ) { ParameterlessConstructorStrategyBlocklist.TryAdd(key, StrategyUnavailableSentinel); } private static bool TryGetTypedParameterlessConstructorFromCache( CapabilityKey<(ConstructorInfo ctor, Type instance)> key, out Delegate creator ) { return TypedParameterlessConstructors.TryGetValue(key, out creator); } private static Delegate AddOrGetTypedParameterlessConstructor( CapabilityKey<(ConstructorInfo ctor, Type instance)> key, Delegate creator ) { return TypedParameterlessConstructors.GetOrAdd(key, creator); } private static bool IsTypedParameterlessConstructorStrategyUnavailable( CapabilityKey<(ConstructorInfo ctor, Type instance)> key ) { return TypedParameterlessConstructorStrategyBlocklist.ContainsKey(key); } private static void MarkTypedParameterlessConstructorStrategyUnavailable( CapabilityKey<(ConstructorInfo ctor, Type instance)> key ) { TypedParameterlessConstructorStrategyBlocklist.TryAdd( key, StrategyUnavailableSentinel ); } private static bool TryGetTypedFieldGetterFromCache( CapabilityKey<(FieldInfo field, Type instance, Type value)> key, out Delegate getter ) { return TypedFieldGetters.TryGetValue(key, out getter); } private static Delegate AddOrGetTypedFieldGetter( CapabilityKey<(FieldInfo field, Type instance, Type value)> key, Delegate getter ) { return TypedFieldGetters.GetOrAdd(key, getter); } private static bool IsTypedFieldGetterStrategyUnavailable( CapabilityKey<(FieldInfo field, Type instance, Type value)> key ) { return TypedFieldGetterStrategyBlocklist.ContainsKey(key); } private static void MarkTypedFieldGetterStrategyUnavailable( CapabilityKey<(FieldInfo field, Type instance, Type value)> key ) { TypedFieldGetterStrategyBlocklist.TryAdd(key, StrategyUnavailableSentinel); } private static bool TryGetTypedFieldSetterFromCache( CapabilityKey<(FieldInfo field, Type instance, Type value)> key, out Delegate setter ) { return TypedFieldSetters.TryGetValue(key, out setter); } private static Delegate AddOrGetTypedFieldSetter( CapabilityKey<(FieldInfo field, Type instance, Type value)> key, Delegate setter ) { return TypedFieldSetters.GetOrAdd(key, setter); } private static bool IsTypedFieldSetterStrategyUnavailable( CapabilityKey<(FieldInfo field, Type instance, Type value)> key ) { return TypedFieldSetterStrategyBlocklist.ContainsKey(key); } private static void MarkTypedFieldSetterStrategyUnavailable( CapabilityKey<(FieldInfo field, Type instance, Type value)> key ) { TypedFieldSetterStrategyBlocklist.TryAdd(key, StrategyUnavailableSentinel); } private static bool TryGetTypedStaticFieldGetterFromCache( CapabilityKey<(FieldInfo field, Type value)> key, out Delegate getter ) { return TypedStaticFieldGetters.TryGetValue(key, out getter); } private static Delegate AddOrGetTypedStaticFieldGetter( CapabilityKey<(FieldInfo field, Type value)> key, Delegate getter ) { return TypedStaticFieldGetters.GetOrAdd(key, getter); } private static bool IsTypedStaticFieldGetterStrategyUnavailable( CapabilityKey<(FieldInfo field, Type value)> key ) { return TypedStaticFieldGetterStrategyBlocklist.ContainsKey(key); } private static void MarkTypedStaticFieldGetterStrategyUnavailable( CapabilityKey<(FieldInfo field, Type value)> key ) { TypedStaticFieldGetterStrategyBlocklist.TryAdd(key, StrategyUnavailableSentinel); } private static bool TryGetTypedStaticFieldSetterFromCache( CapabilityKey<(FieldInfo field, Type value)> key, out Delegate setter ) { return TypedStaticFieldSetters.TryGetValue(key, out setter); } private static Delegate AddOrGetTypedStaticFieldSetter( CapabilityKey<(FieldInfo field, Type value)> key, Delegate setter ) { return TypedStaticFieldSetters.GetOrAdd(key, setter); } private static bool IsTypedStaticFieldSetterStrategyUnavailable( CapabilityKey<(FieldInfo field, Type value)> key ) { return TypedStaticFieldSetterStrategyBlocklist.ContainsKey(key); } private static void MarkTypedStaticFieldSetterStrategyUnavailable( CapabilityKey<(FieldInfo field, Type value)> key ) { TypedStaticFieldSetterStrategyBlocklist.TryAdd(key, StrategyUnavailableSentinel); } #else private static bool TryGetFieldGetterFromCache( CapabilityKey key, out Func getter ) { return FieldGetters.TryGetValue(key, out getter); } private static Func AddOrGetFieldGetter( CapabilityKey key, Func getter ) { if (FieldGetters.TryGetValue(key, out Func existing)) { return existing; } FieldGetters[key] = getter; return getter; } private static bool IsFieldGetterStrategyUnavailable(CapabilityKey key) { return FieldGetterStrategyBlocklist.Contains(key); } private static void MarkFieldGetterStrategyUnavailable(CapabilityKey key) { FieldGetterStrategyBlocklist.Add(key); } private static bool TryGetFieldSetterFromCache( CapabilityKey key, out Action setter ) { return FieldSetters.TryGetValue(key, out setter); } private static Action AddOrGetFieldSetter( CapabilityKey key, Action setter ) { if (FieldSetters.TryGetValue(key, out Action existing)) { return existing; } FieldSetters[key] = setter; return setter; } private static bool IsFieldSetterStrategyUnavailable(CapabilityKey key) { return FieldSetterStrategyBlocklist.Contains(key); } private static void MarkFieldSetterStrategyUnavailable(CapabilityKey key) { FieldSetterStrategyBlocklist.Add(key); } private static bool TryGetStaticFieldGetterFromCache( CapabilityKey key, out Func getter ) { return StaticFieldGetters.TryGetValue(key, out getter); } private static Func AddOrGetStaticFieldGetter( CapabilityKey key, Func getter ) { if (StaticFieldGetters.TryGetValue(key, out Func existing)) { return existing; } StaticFieldGetters[key] = getter; return getter; } private static bool IsStaticFieldGetterStrategyUnavailable(CapabilityKey key) { return StaticFieldGetterStrategyBlocklist.Contains(key); } private static void MarkStaticFieldGetterStrategyUnavailable( CapabilityKey key ) { StaticFieldGetterStrategyBlocklist.Add(key); } private static bool TryGetStaticFieldSetterFromCache( CapabilityKey key, out Action setter ) { return StaticFieldSetters.TryGetValue(key, out setter); } private static Action AddOrGetStaticFieldSetter( CapabilityKey key, Action setter ) { if (StaticFieldSetters.TryGetValue(key, out Action existing)) { return existing; } StaticFieldSetters[key] = setter; return setter; } private static bool IsStaticFieldSetterStrategyUnavailable(CapabilityKey key) { return StaticFieldSetterStrategyBlocklist.Contains(key); } private static void MarkStaticFieldSetterStrategyUnavailable( CapabilityKey key ) { StaticFieldSetterStrategyBlocklist.Add(key); } private static bool TryGetPropertyGetterFromCache( CapabilityKey key, out Func getter ) { return PropertyGetters.TryGetValue(key, out getter); } private static Func AddOrGetPropertyGetter( CapabilityKey key, Func getter ) { if (PropertyGetters.TryGetValue(key, out Func existing)) { return existing; } PropertyGetters[key] = getter; return getter; } private static bool IsPropertyGetterStrategyUnavailable(CapabilityKey key) { return PropertyGetterStrategyBlocklist.Contains(key); } private static void MarkPropertyGetterStrategyUnavailable( CapabilityKey key ) { PropertyGetterStrategyBlocklist.Add(key); } private static bool TryGetPropertySetterFromCache( CapabilityKey key, out Action setter ) { return PropertySetters.TryGetValue(key, out setter); } private static Action AddOrGetPropertySetter( CapabilityKey key, Action setter ) { if (PropertySetters.TryGetValue(key, out Action existing)) { return existing; } PropertySetters[key] = setter; return setter; } private static bool IsPropertySetterStrategyUnavailable(CapabilityKey key) { return PropertySetterStrategyBlocklist.Contains(key); } private static void MarkPropertySetterStrategyUnavailable( CapabilityKey key ) { PropertySetterStrategyBlocklist.Add(key); } private static bool TryGetIndexerGetterFromCache( CapabilityKey key, out Func getter ) { return IndexerGetters.TryGetValue(key, out getter); } private static Func AddOrGetIndexerGetter( CapabilityKey key, Func getter ) { if (IndexerGetters.TryGetValue(key, out Func existing)) { return existing; } IndexerGetters[key] = getter; return getter; } private static bool IsIndexerGetterStrategyUnavailable(CapabilityKey key) { return IndexerGetterStrategyBlocklist.ContainsKey(key); } private static void MarkIndexerGetterStrategyUnavailable( CapabilityKey key ) { IndexerGetterStrategyBlocklist[key] = StrategyUnavailableSentinel; } private static bool TryGetIndexerSetterFromCache( CapabilityKey key, out Action setter ) { return IndexerSetters.TryGetValue(key, out setter); } private static Action AddOrGetIndexerSetter( CapabilityKey key, Action setter ) { if (IndexerSetters.TryGetValue(key, out Action existing)) { return existing; } IndexerSetters[key] = setter; return setter; } private static bool IsIndexerSetterStrategyUnavailable(CapabilityKey key) { return IndexerSetterStrategyBlocklist.ContainsKey(key); } private static void MarkIndexerSetterStrategyUnavailable( CapabilityKey key ) { IndexerSetterStrategyBlocklist[key] = StrategyUnavailableSentinel; } private static bool TryGetMethodInvokerFromCache( CapabilityKey key, out Func invoker ) { return MethodInvokers.TryGetValue(key, out invoker); } private static Func AddOrGetMethodInvoker( CapabilityKey key, Func invoker ) { if (MethodInvokers.TryGetValue(key, out Func existing)) { return existing; } MethodInvokers[key] = invoker; return invoker; } private static bool IsMethodInvokerStrategyUnavailable(CapabilityKey key) { return MethodInvokerStrategyBlocklist.ContainsKey(key); } private static void MarkMethodInvokerStrategyUnavailable(CapabilityKey key) { MethodInvokerStrategyBlocklist[key] = StrategyUnavailableSentinel; } private static bool TryGetStaticMethodInvokerFromCache( CapabilityKey key, out Func invoker ) { return StaticMethodInvokers.TryGetValue(key, out invoker); } private static Func AddOrGetStaticMethodInvoker( CapabilityKey key, Func invoker ) { if (StaticMethodInvokers.TryGetValue(key, out Func existing)) { return existing; } StaticMethodInvokers[key] = invoker; return invoker; } private static bool IsStaticMethodInvokerStrategyUnavailable( CapabilityKey key ) { return StaticMethodInvokerStrategyBlocklist.Contains(key); } private static void MarkStaticMethodInvokerStrategyUnavailable( CapabilityKey key ) { StaticMethodInvokerStrategyBlocklist.Add(key); } private static bool TryGetConstructorInvokerFromCache( CapabilityKey key, out Func invoker ) { return Constructors.TryGetValue(key, out invoker); } private static Func AddOrGetConstructorInvoker( CapabilityKey key, Func invoker ) { if (Constructors.TryGetValue(key, out Func existing)) { return existing; } Constructors[key] = invoker; return invoker; } private static bool IsConstructorInvokerStrategyUnavailable( CapabilityKey key ) { return ConstructorInvokerStrategyBlocklist.Contains(key); } private static void MarkConstructorInvokerStrategyUnavailable( CapabilityKey key ) { ConstructorInvokerStrategyBlocklist.Add(key); } private static bool TryGetParameterlessConstructorFromCache( CapabilityKey key, out Func creator ) { return ParameterlessConstructors.TryGetValue(key, out creator); } private static Func AddOrGetParameterlessConstructor( CapabilityKey key, Func creator ) { if (ParameterlessConstructors.TryGetValue(key, out Func existing)) { return existing; } ParameterlessConstructors[key] = creator; return creator; } private static bool IsParameterlessConstructorStrategyUnavailable( CapabilityKey key ) { return ParameterlessConstructorStrategyBlocklist.Contains(key); } private static void MarkParameterlessConstructorStrategyUnavailable( CapabilityKey key ) { ParameterlessConstructorStrategyBlocklist.Add(key); } private static bool TryGetTypedParameterlessConstructorFromCache( CapabilityKey<(ConstructorInfo ctor, Type instance)> key, out Delegate creator ) { return TypedParameterlessConstructors.TryGetValue(key, out creator); } private static Delegate AddOrGetTypedParameterlessConstructor( CapabilityKey<(ConstructorInfo ctor, Type instance)> key, Delegate creator ) { if (TypedParameterlessConstructors.TryGetValue(key, out Delegate existing)) { return existing; } TypedParameterlessConstructors[key] = creator; return creator; } private static bool IsTypedParameterlessConstructorStrategyUnavailable( CapabilityKey<(ConstructorInfo ctor, Type instance)> key ) { return TypedParameterlessConstructorStrategyBlocklist.Contains(key); } private static void MarkTypedParameterlessConstructorStrategyUnavailable( CapabilityKey<(ConstructorInfo ctor, Type instance)> key ) { TypedParameterlessConstructorStrategyBlocklist.Add(key); } private static bool TryGetTypedFieldGetterFromCache( CapabilityKey<(FieldInfo field, Type instance, Type value)> key, out Delegate getter ) { return TypedFieldGetters.TryGetValue(key, out getter); } private static Delegate AddOrGetTypedFieldGetter( CapabilityKey<(FieldInfo field, Type instance, Type value)> key, Delegate getter ) { if (TypedFieldGetters.TryGetValue(key, out Delegate existing)) { return existing; } TypedFieldGetters[key] = getter; return getter; } private static bool IsTypedFieldGetterStrategyUnavailable( CapabilityKey<(FieldInfo field, Type instance, Type value)> key ) { return TypedFieldGetterStrategyBlocklist.Contains(key); } private static void MarkTypedFieldGetterStrategyUnavailable( CapabilityKey<(FieldInfo field, Type instance, Type value)> key ) { TypedFieldGetterStrategyBlocklist.Add(key); } private static bool TryGetTypedFieldSetterFromCache( CapabilityKey<(FieldInfo field, Type instance, Type value)> key, out Delegate setter ) { return TypedFieldSetters.TryGetValue(key, out setter); } private static Delegate AddOrGetTypedFieldSetter( CapabilityKey<(FieldInfo field, Type instance, Type value)> key, Delegate setter ) { if (TypedFieldSetters.TryGetValue(key, out Delegate existing)) { return existing; } TypedFieldSetters[key] = setter; return setter; } private static bool IsTypedFieldSetterStrategyUnavailable( CapabilityKey<(FieldInfo field, Type instance, Type value)> key ) { return TypedFieldSetterStrategyBlocklist.Contains(key); } private static void MarkTypedFieldSetterStrategyUnavailable( CapabilityKey<(FieldInfo field, Type instance, Type value)> key ) { TypedFieldSetterStrategyBlocklist.Add(key); } private static bool TryGetTypedStaticFieldGetterFromCache( CapabilityKey<(FieldInfo field, Type value)> key, out Delegate getter ) { return TypedStaticFieldGetters.TryGetValue(key, out getter); } private static Delegate AddOrGetTypedStaticFieldGetter( CapabilityKey<(FieldInfo field, Type value)> key, Delegate getter ) { if (TypedStaticFieldGetters.TryGetValue(key, out Delegate existing)) { return existing; } TypedStaticFieldGetters[key] = getter; return getter; } private static bool IsTypedStaticFieldGetterStrategyUnavailable( CapabilityKey<(FieldInfo field, Type value)> key ) { return TypedStaticFieldGetterStrategyBlocklist.Contains(key); } private static void MarkTypedStaticFieldGetterStrategyUnavailable( CapabilityKey<(FieldInfo field, Type value)> key ) { TypedStaticFieldGetterStrategyBlocklist.Add(key); } private static bool TryGetTypedStaticFieldSetterFromCache( CapabilityKey<(FieldInfo field, Type value)> key, out Delegate setter ) { return TypedStaticFieldSetters.TryGetValue(key, out setter); } private static Delegate AddOrGetTypedStaticFieldSetter( CapabilityKey<(FieldInfo field, Type value)> key, Delegate setter ) { if (TypedStaticFieldSetters.TryGetValue(key, out Delegate existing)) { return existing; } TypedStaticFieldSetters[key] = setter; return setter; } private static bool IsTypedStaticFieldSetterStrategyUnavailable( CapabilityKey<(FieldInfo field, Type value)> key ) { return TypedStaticFieldSetterStrategyBlocklist.Contains(key); } private static void MarkTypedStaticFieldSetterStrategyUnavailable( CapabilityKey<(FieldInfo field, Type value)> key ) { TypedStaticFieldSetterStrategyBlocklist.Add(key); } #endif private static void TrackDelegateStrategy( Delegate delegateInstance, CapabilityKey key ) { if (delegateInstance == null) { return; } StrategyHolder holder = StrategyHolder.Create(key, delegateInstance.GetType()); DelegateStrategyTable.Remove(delegateInstance); DelegateStrategyTable.Add(delegateInstance, holder); } public static void ClearFieldGetterCache() { #if !SINGLE_THREADED FieldGetters.Clear(); FieldGetterStrategyBlocklist.Clear(); StaticFieldGetters.Clear(); StaticFieldGetterStrategyBlocklist.Clear(); TypedFieldGetters.Clear(); TypedFieldGetterStrategyBlocklist.Clear(); TypedStaticFieldGetters.Clear(); TypedStaticFieldGetterStrategyBlocklist.Clear(); #else FieldGetters.Clear(); FieldGetterStrategyBlocklist.Clear(); StaticFieldGetters.Clear(); StaticFieldGetterStrategyBlocklist.Clear(); TypedFieldGetters.Clear(); TypedFieldGetterStrategyBlocklist.Clear(); TypedStaticFieldGetters.Clear(); TypedStaticFieldGetterStrategyBlocklist.Clear(); #endif } public static void ClearFieldSetterCache() { #if !SINGLE_THREADED FieldSetters.Clear(); FieldSetterStrategyBlocklist.Clear(); StaticFieldSetters.Clear(); StaticFieldSetterStrategyBlocklist.Clear(); TypedFieldSetters.Clear(); TypedFieldSetterStrategyBlocklist.Clear(); TypedStaticFieldSetters.Clear(); TypedStaticFieldSetterStrategyBlocklist.Clear(); #else FieldSetters.Clear(); FieldSetterStrategyBlocklist.Clear(); StaticFieldSetters.Clear(); StaticFieldSetterStrategyBlocklist.Clear(); TypedFieldSetters.Clear(); TypedFieldSetterStrategyBlocklist.Clear(); TypedStaticFieldSetters.Clear(); TypedStaticFieldSetterStrategyBlocklist.Clear(); #endif } public static void ClearPropertyCache() { #if !SINGLE_THREADED PropertyGetters.Clear(); PropertyGetterStrategyBlocklist.Clear(); PropertySetters.Clear(); PropertySetterStrategyBlocklist.Clear(); TypedPropertyGetters.Clear(); TypedPropertySetters.Clear(); TypedStaticPropertyGetters.Clear(); TypedStaticPropertySetters.Clear(); IndexerGetters.Clear(); IndexerGetterStrategyBlocklist.Clear(); IndexerSetters.Clear(); IndexerSetterStrategyBlocklist.Clear(); #else PropertyGetters.Clear(); PropertyGetterStrategyBlocklist.Clear(); PropertySetters.Clear(); PropertySetterStrategyBlocklist.Clear(); TypedPropertyGetters.Clear(); TypedPropertySetters.Clear(); TypedStaticPropertyGetters.Clear(); TypedStaticPropertySetters.Clear(); IndexerGetters.Clear(); IndexerGetterStrategyBlocklist.Clear(); IndexerSetters.Clear(); IndexerSetterStrategyBlocklist.Clear(); #endif } public static void ClearMethodCache() { #if !SINGLE_THREADED MethodInvokers.Clear(); MethodInvokerStrategyBlocklist.Clear(); StaticMethodInvokers.Clear(); StaticMethodInvokerStrategyBlocklist.Clear(); #else MethodInvokers.Clear(); MethodInvokerStrategyBlocklist.Clear(); StaticMethodInvokers.Clear(); StaticMethodInvokerStrategyBlocklist.Clear(); #endif } public static void ClearConstructorCache() { #if !SINGLE_THREADED Constructors.Clear(); ConstructorInvokerStrategyBlocklist.Clear(); ParameterlessConstructors.Clear(); ParameterlessConstructorStrategyBlocklist.Clear(); TypedParameterlessConstructors.Clear(); TypedParameterlessConstructorStrategyBlocklist.Clear(); #else Constructors.Clear(); ConstructorInvokerStrategyBlocklist.Clear(); ParameterlessConstructors.Clear(); ParameterlessConstructorStrategyBlocklist.Clear(); TypedParameterlessConstructors.Clear(); TypedParameterlessConstructorStrategyBlocklist.Clear(); #endif } public static bool TryGetStrategy( Delegate delegateInstance, out ReflectionDelegateStrategy strategy ) { if (delegateInstance == null) { strategy = ReflectionDelegateStrategy.Reflection; return false; } if (DelegateStrategyTable.TryGetValue(delegateInstance, out StrategyHolder holder)) { strategy = holder.Strategy; return true; } strategy = ReflectionDelegateStrategy.Reflection; return false; } private static Func CreatePropertyGetter( PropertyInfo property, ReflectionDelegateStrategy strategy ) { if (strategy == ReflectionDelegateStrategy.Expressions) { return CreateCompiledPropertyGetter(property); } #if EMIT_DYNAMIC_IL if (strategy == ReflectionDelegateStrategy.DynamicIl) { return BuildPropertyGetterIL(property); } #endif if (strategy == ReflectionDelegateStrategy.Reflection) { return CreateReflectionPropertyGetter(property); } return null; } private static Action CreatePropertySetter( PropertyInfo property, ReflectionDelegateStrategy strategy ) { if (strategy == ReflectionDelegateStrategy.Expressions) { return CreateCompiledPropertySetter(property); } #if EMIT_DYNAMIC_IL if (strategy == ReflectionDelegateStrategy.DynamicIl) { return BuildPropertySetterIL(property); } #endif if (strategy == ReflectionDelegateStrategy.Reflection) { return CreateReflectionPropertySetter(property); } return null; } private static Func CreateReflectionPropertyGetter( PropertyInfo property ) { if (property.GetMethod != null && property.GetMethod.IsStatic) { return _ => property.GetValue(null); } return instance => property.GetValue(instance); } private static Action CreateReflectionPropertySetter( PropertyInfo property ) { if (property.SetMethod != null && property.SetMethod.IsStatic) { return (_, value) => property.SetValue(null, value); } return (instance, value) => property.SetValue(instance, value); } private static bool TryGetOrCreateMethodInvoker( MethodInfo method, ReflectionDelegateStrategy strategy, out Func invoker ) { invoker = null; if (strategy == ReflectionDelegateStrategy.Expressions && !SupportsExpressions) { return false; } #if EMIT_DYNAMIC_IL if (strategy == ReflectionDelegateStrategy.DynamicIl && !SupportsDynamicIl) { return false; } #else if (strategy == ReflectionDelegateStrategy.DynamicIl) { return false; } #endif CapabilityKey key = new(method, strategy); if (TryGetMethodInvokerFromCache(key, out Func cached)) { invoker = cached; return true; } if (IsMethodInvokerStrategyUnavailable(key)) { return false; } Func candidate = CreateMethodInvoker(method, strategy); if (candidate == null) { MarkMethodInvokerStrategyUnavailable(key); return false; } Func resolved = AddOrGetMethodInvoker(key, candidate); TrackDelegateStrategy(resolved, key); invoker = resolved; return true; } private static Func GetOrCreateReflectionMethodInvoker( MethodInfo method ) { CapabilityKey key = new(method, ReflectionDelegateStrategy.Reflection); if (TryGetMethodInvokerFromCache(key, out Func cached)) { return cached; } Func reflectionInvoker = CreateReflectionMethodInvoker( method ); Func resolved = AddOrGetMethodInvoker( key, reflectionInvoker ); TrackDelegateStrategy(resolved, key); return resolved; } private static bool TryGetOrCreateStaticMethodInvoker( MethodInfo method, ReflectionDelegateStrategy strategy, out Func invoker ) { invoker = null; if (strategy == ReflectionDelegateStrategy.Expressions && !SupportsExpressions) { return false; } #if EMIT_DYNAMIC_IL if (strategy == ReflectionDelegateStrategy.DynamicIl && !SupportsDynamicIl) { return false; } #else if (strategy == ReflectionDelegateStrategy.DynamicIl) { return false; } #endif CapabilityKey key = new(method, strategy); if (TryGetStaticMethodInvokerFromCache(key, out Func cached)) { invoker = cached; return true; } if (IsStaticMethodInvokerStrategyUnavailable(key)) { return false; } Func candidate = CreateStaticMethodInvoker(method, strategy); if (candidate == null) { MarkStaticMethodInvokerStrategyUnavailable(key); return false; } Func resolved = AddOrGetStaticMethodInvoker(key, candidate); TrackDelegateStrategy(resolved, key); invoker = resolved; return true; } private static Func GetOrCreateReflectionStaticMethodInvoker( MethodInfo method ) { CapabilityKey key = new(method, ReflectionDelegateStrategy.Reflection); if (TryGetStaticMethodInvokerFromCache(key, out Func cached)) { return cached; } Func reflectionInvoker = CreateReflectionStaticMethodInvoker( method ); Func resolved = AddOrGetStaticMethodInvoker( key, reflectionInvoker ); TrackDelegateStrategy(resolved, key); return resolved; } private static Func CreateMethodInvoker( MethodInfo method, ReflectionDelegateStrategy strategy ) { if (strategy == ReflectionDelegateStrategy.Expressions) { return CreateCompiledMethodInvoker(method); } #if EMIT_DYNAMIC_IL if (strategy == ReflectionDelegateStrategy.DynamicIl) { return BuildMethodInvokerIL(method); } #endif return null; } private static Func CreateReflectionMethodInvoker( MethodInfo method ) { return (instance, args) => method.Invoke(instance, args); } private static Func CreateStaticMethodInvoker( MethodInfo method, ReflectionDelegateStrategy strategy ) { if (strategy == ReflectionDelegateStrategy.Expressions) { return CreateCompiledStaticMethodInvoker(method); } #if EMIT_DYNAMIC_IL if (strategy == ReflectionDelegateStrategy.DynamicIl) { return BuildStaticMethodInvokerIL(method); } #endif return null; } private static Func CreateReflectionStaticMethodInvoker( MethodInfo method ) { return args => method.Invoke(null, args); } private static Func CreateConstructorInvoker( ConstructorInfo ctor, ReflectionDelegateStrategy strategy ) { if (strategy == ReflectionDelegateStrategy.Expressions) { if (SupportsExpressions) { Func invoker = CreateCompiledConstructor(ctor); if (invoker != null) { return invoker; } } } #if EMIT_DYNAMIC_IL if (strategy == ReflectionDelegateStrategy.DynamicIl && SupportsDynamicIl) { return BuildConstructorIL(ctor); } #endif if (strategy == ReflectionDelegateStrategy.Reflection) { return args => ctor.Invoke(args); } return null; } private static Func CreateReflectionConstructorInvoker( ConstructorInfo ctor ) { return args => ctor.Invoke(args); } private static Func CreateParameterlessConstructor( ConstructorInfo ctor, ReflectionDelegateStrategy strategy ) { if (strategy == ReflectionDelegateStrategy.Expressions) { if (SupportsExpressions) { Func creator = CreateCompiledParameterlessConstructor(ctor); if (creator != null) { return creator; } } } #if EMIT_DYNAMIC_IL if (strategy == ReflectionDelegateStrategy.DynamicIl && SupportsDynamicIl) { return BuildParameterlessConstructorIL(ctor); } #endif if (strategy == ReflectionDelegateStrategy.Reflection) { return () => ctor.Invoke(null); } return null; } private static Func CreateTypedParameterlessConstructor( ConstructorInfo ctor, ReflectionDelegateStrategy strategy ) { if (strategy == ReflectionDelegateStrategy.Expressions) { if (SupportsExpressions) { Func creator = CreateCompiledParameterlessConstructor(ctor); if (creator != null) { return creator; } } } #if EMIT_DYNAMIC_IL if (strategy == ReflectionDelegateStrategy.DynamicIl && SupportsDynamicIl) { return BuildTypedParameterlessConstructorIL(ctor); } #endif if (strategy == ReflectionDelegateStrategy.Reflection) { return () => (T)ctor.Invoke(null); } return null; } private static Func BuildTypedPropertyGetter( PropertyInfo property ) { if (property == null) { throw new ArgumentNullException(nameof(property)); } MethodInfo getMethod = property.GetGetMethod(true) ?? throw new ArgumentException( $"Property {property?.Name} has no getter", nameof(property) ); Func getter = null; if (SupportsExpressions) { getter = CreateCompiledTypedPropertyGetter( property, getMethod ); } #if EMIT_DYNAMIC_IL if ( getter == null && SupportsDynamicIl && CanInlineReturnConversion(property.PropertyType, typeof(TValue)) ) { getter = BuildTypedPropertyGetterIL(property, getMethod); } #endif if (getter != null) { return getter; } if (getMethod.IsStatic) { return _ => (TValue)property.GetValue(null); } return instance => (TValue)property.GetValue(instance); } private static Action BuildTypedPropertySetter( PropertyInfo property ) { if (property == null) { throw new ArgumentNullException(nameof(property)); } MethodInfo setMethod = property.GetSetMethod(true) ?? throw new ArgumentException( $"Property {property?.Name} has no setter", nameof(property) ); Action setter = null; if (SupportsExpressions) { setter = CreateCompiledTypedPropertySetter( property, setMethod ); } #if EMIT_DYNAMIC_IL if ( setter == null && SupportsDynamicIl && CanInlineAssignment(typeof(TValue), property.PropertyType) ) { setter = BuildTypedPropertySetterIL(property, setMethod); } #endif if (setter != null) { return setter; } if (setMethod.IsStatic) { return (_, value) => property.SetValue(null, value); } return (instance, value) => property.SetValue(instance, value); } private static Func BuildTypedStaticPropertyGetter( PropertyInfo property ) { if (property == null) { throw new ArgumentNullException(nameof(property)); } MethodInfo getMethod = property.GetGetMethod(true) ?? throw new ArgumentException( $"Property {property?.Name} has no getter", nameof(property) ); Func getter = null; if (SupportsExpressions) { getter = CreateCompiledTypedStaticPropertyGetter(property, getMethod); } #if EMIT_DYNAMIC_IL if ( getter == null && SupportsDynamicIl && CanInlineReturnConversion(property.PropertyType, typeof(TValue)) ) { getter = BuildTypedStaticPropertyGetterIL(property, getMethod); } #endif return getter ?? (() => (TValue)property.GetValue(null)); } private static Action BuildTypedStaticPropertySetter( PropertyInfo property ) { if (property == null) { throw new ArgumentNullException(nameof(property)); } MethodInfo setMethod = property.GetSetMethod(true) ?? throw new ArgumentException( $"Property {property?.Name} has no setter", nameof(property) ); Action setter = null; if (SupportsExpressions) { setter = CreateCompiledTypedStaticPropertySetter(property, setMethod); } #if EMIT_DYNAMIC_IL if ( setter == null && SupportsDynamicIl && CanInlineAssignment(typeof(TValue), property.PropertyType) ) { setter = BuildTypedStaticPropertySetterIL(property, setMethod); } #endif return setter ?? (value => property.SetValue(null, value)); } public static Func GetStaticMethodInvokerTyped(MethodInfo method) { if (method == null) { throw new ArgumentNullException(nameof(method)); } #if SINGLE_THREADED if (!TypedStaticInvoker0.TryGetValue(method, out Delegate del)) { del = BuildTypedStaticInvoker0(method); TypedStaticInvoker0[method] = del; } return (Func)del; #else Delegate del = TypedStaticInvoker0.GetOrAdd( method, static m => BuildTypedStaticInvoker0(m) ); return (Func)del; #endif } public static Func GetStaticMethodInvokerTyped( MethodInfo method ) { if (method == null) { throw new ArgumentNullException(nameof(method)); } #if SINGLE_THREADED if (!TypedStaticInvoker1.TryGetValue(method, out Delegate del)) { del = BuildTypedStaticInvoker1(method); TypedStaticInvoker1[method] = del; } return (Func)del; #else Delegate del = TypedStaticInvoker1.GetOrAdd( method, static m => BuildTypedStaticInvoker1(m) ); return (Func)del; #endif } public static Func GetStaticMethodInvokerTyped( MethodInfo method ) { if (method == null) { throw new ArgumentNullException(nameof(method)); } #if SINGLE_THREADED if (!TypedStaticInvoker2.TryGetValue(method, out Delegate del)) { del = BuildTypedStaticInvoker2(method); TypedStaticInvoker2[method] = del; } return (Func)del; #else Delegate del = TypedStaticInvoker2.GetOrAdd( method, static m => BuildTypedStaticInvoker2(m) ); return (Func)del; #endif } public static Func GetStaticMethodInvokerTyped< T1, T2, T3, TReturn >(MethodInfo method) { if (method == null) { throw new ArgumentNullException(nameof(method)); } #if SINGLE_THREADED if (!TypedStaticInvoker3.TryGetValue(method, out Delegate del)) { del = BuildTypedStaticInvoker3(method); TypedStaticInvoker3[method] = del; } return (Func)del; #else Delegate del = TypedStaticInvoker3.GetOrAdd( method, static m => BuildTypedStaticInvoker3(m) ); return (Func)del; #endif } public static Func GetStaticMethodInvokerTyped< T1, T2, T3, T4, TReturn >(MethodInfo method) { if (method == null) { throw new ArgumentNullException(nameof(method)); } #if SINGLE_THREADED if (!TypedStaticInvoker4.TryGetValue(method, out Delegate del)) { del = BuildTypedStaticInvoker4(method); TypedStaticInvoker4[method] = del; } return (Func)del; #else Delegate del = TypedStaticInvoker4.GetOrAdd( method, static m => BuildTypedStaticInvoker4(m) ); return (Func)del; #endif } public static Action GetStaticActionInvokerTyped(MethodInfo method) { if (method == null) { throw new ArgumentNullException(nameof(method)); } #if SINGLE_THREADED if (!TypedStaticAction0.TryGetValue(method, out Delegate del)) { del = BuildStaticActionInvoker0(method); TypedStaticAction0[method] = del; } return (Action)del; #else Delegate del = TypedStaticAction0.GetOrAdd( method, static m => BuildStaticActionInvoker0(m) ); return (Action)del; #endif } public static Action GetStaticActionInvokerTyped(MethodInfo method) { if (method == null) { throw new ArgumentNullException(nameof(method)); } #if SINGLE_THREADED if (!TypedStaticAction1.TryGetValue(method, out Delegate del)) { del = BuildStaticActionInvoker1(method); TypedStaticAction1[method] = del; } return (Action)del; #else Delegate del = TypedStaticAction1.GetOrAdd( method, static m => BuildStaticActionInvoker1(m) ); return (Action)del; #endif } public static Action GetStaticActionInvokerTyped(MethodInfo method) { if (method == null) { throw new ArgumentNullException(nameof(method)); } #if SINGLE_THREADED if (!TypedStaticAction2.TryGetValue(method, out Delegate del)) { del = BuildStaticActionInvoker2(method); TypedStaticAction2[method] = del; } return (Action)del; #else Delegate del = TypedStaticAction2.GetOrAdd( method, static m => BuildStaticActionInvoker2(m) ); return (Action)del; #endif } public static Action GetStaticActionInvokerTyped( MethodInfo method ) { if (method == null) { throw new ArgumentNullException(nameof(method)); } #if SINGLE_THREADED if (!TypedStaticAction3.TryGetValue(method, out Delegate del)) { del = BuildStaticActionInvoker3(method); TypedStaticAction3[method] = del; } return (Action)del; #else Delegate del = TypedStaticAction3.GetOrAdd( method, static m => BuildStaticActionInvoker3(m) ); return (Action)del; #endif } public static Action GetStaticActionInvokerTyped( MethodInfo method ) { if (method == null) { throw new ArgumentNullException(nameof(method)); } #if SINGLE_THREADED if (!TypedStaticAction4.TryGetValue(method, out Delegate del)) { del = BuildStaticActionInvoker4(method); TypedStaticAction4[method] = del; } return (Action)del; #else Delegate del = TypedStaticAction4.GetOrAdd( method, static m => BuildStaticActionInvoker4(m) ); return (Action)del; #endif } public static Func GetInstanceMethodInvokerTyped< TInstance, TReturn >(MethodInfo method) { if (method == null) { throw new ArgumentNullException(nameof(method)); } #if SINGLE_THREADED if (!TypedInstanceInvoker0.TryGetValue(method, out Delegate del)) { del = BuildInstanceInvoker0(method); TypedInstanceInvoker0[method] = del; } return (Func)del; #else Delegate del = TypedInstanceInvoker0.GetOrAdd( method, static m => BuildInstanceInvoker0(m) ); return (Func)del; #endif } public static Func GetInstanceMethodInvokerTyped< TInstance, T1, TReturn >(MethodInfo method) { if (method == null) { throw new ArgumentNullException(nameof(method)); } #if SINGLE_THREADED if (!TypedInstanceInvoker1.TryGetValue(method, out Delegate del)) { del = BuildInstanceInvoker1(method); TypedInstanceInvoker1[method] = del; } return (Func)del; #else Delegate del = TypedInstanceInvoker1.GetOrAdd( method, static m => BuildInstanceInvoker1(m) ); return (Func)del; #endif } public static Func GetInstanceMethodInvokerTyped< TInstance, T1, T2, TReturn >(MethodInfo method) { if (method == null) { throw new ArgumentNullException(nameof(method)); } #if SINGLE_THREADED if (!TypedInstanceInvoker2.TryGetValue(method, out Delegate del)) { del = BuildInstanceInvoker2(method); TypedInstanceInvoker2[method] = del; } return (Func)del; #else Delegate del = TypedInstanceInvoker2.GetOrAdd( method, static m => BuildInstanceInvoker2(m) ); return (Func)del; #endif } public static Func GetInstanceMethodInvokerTyped< TInstance, T1, T2, T3, TReturn >(MethodInfo method) { if (method == null) { throw new ArgumentNullException(nameof(method)); } #if SINGLE_THREADED if (!TypedInstanceInvoker3.TryGetValue(method, out Delegate del)) { del = BuildInstanceInvoker3(method); TypedInstanceInvoker3[method] = del; } return (Func)del; #else Delegate del = TypedInstanceInvoker3.GetOrAdd( method, static m => BuildInstanceInvoker3(m) ); return (Func)del; #endif } public static Func GetInstanceMethodInvokerTyped< TInstance, T1, T2, T3, T4, TReturn >(MethodInfo method) { if (method == null) { throw new ArgumentNullException(nameof(method)); } #if SINGLE_THREADED if (!TypedInstanceInvoker4.TryGetValue(method, out Delegate del)) { del = BuildInstanceInvoker4(method); TypedInstanceInvoker4[method] = del; } return (Func)del; #else Delegate del = TypedInstanceInvoker4.GetOrAdd( method, static m => BuildInstanceInvoker4(m) ); return (Func)del; #endif } public static Action GetInstanceActionInvokerTyped( MethodInfo method ) { if (method == null) { throw new ArgumentNullException(nameof(method)); } #if SINGLE_THREADED if (!TypedInstanceAction0.TryGetValue(method, out Delegate del)) { del = BuildInstanceActionInvoker0(method); TypedInstanceAction0[method] = del; } return (Action)del; #else Delegate del = TypedInstanceAction0.GetOrAdd( method, static m => BuildInstanceActionInvoker0(m) ); return (Action)del; #endif } public static Action GetInstanceActionInvokerTyped( MethodInfo method ) { if (method == null) { throw new ArgumentNullException(nameof(method)); } #if SINGLE_THREADED if (!TypedInstanceAction1.TryGetValue(method, out Delegate del)) { del = BuildInstanceActionInvoker1(method); TypedInstanceAction1[method] = del; } return (Action)del; #else Delegate del = TypedInstanceAction1.GetOrAdd( method, static m => BuildInstanceActionInvoker1(m) ); return (Action)del; #endif } public static Action GetInstanceActionInvokerTyped< TInstance, T1, T2 >(MethodInfo method) { if (method == null) { throw new ArgumentNullException(nameof(method)); } #if SINGLE_THREADED if (!TypedInstanceAction2.TryGetValue(method, out Delegate del)) { del = BuildInstanceActionInvoker2(method); TypedInstanceAction2[method] = del; } return (Action)del; #else Delegate del = TypedInstanceAction2.GetOrAdd( method, static m => BuildInstanceActionInvoker2(m) ); return (Action)del; #endif } public static Action GetInstanceActionInvokerTyped< TInstance, T1, T2, T3 >(MethodInfo method) { if (method == null) { throw new ArgumentNullException(nameof(method)); } #if SINGLE_THREADED if (!TypedInstanceAction3.TryGetValue(method, out Delegate del)) { del = BuildInstanceActionInvoker3(method); TypedInstanceAction3[method] = del; } return (Action)del; #else Delegate del = TypedInstanceAction3.GetOrAdd( method, static m => BuildInstanceActionInvoker3(m) ); return (Action)del; #endif } public static Action GetInstanceActionInvokerTyped< TInstance, T1, T2, T3, T4 >(MethodInfo method) { if (method == null) { throw new ArgumentNullException(nameof(method)); } #if SINGLE_THREADED if (!TypedInstanceAction4.TryGetValue(method, out Delegate del)) { del = BuildInstanceActionInvoker4(method); TypedInstanceAction4[method] = del; } return (Action)del; #else Delegate del = TypedInstanceAction4.GetOrAdd( method, static m => BuildInstanceActionInvoker4(m) ); return (Action)del; #endif } } } }