1 // Licensed to the .NET Foundation under one or more agreements.
2 // The .NET Foundation licenses this file to you under the MIT license.
5 using System.Collections.Generic;
6 using System.Diagnostics.CodeAnalysis;
8 using System.Reflection;
9 using System.Runtime.CompilerServices;
10 using System.Runtime.Serialization;
11 using System.Runtime.Serialization.DataContracts;
13 using System.Threading.Tasks;
15 namespace System.Runtime.Serialization
17 internal static class FastInvokerBuilder
19 public delegate void Setter(ref object obj, object? value);
20 public delegate object? Getter(object obj);
22 private delegate void StructSetDelegate<T, TArg>(ref T obj, TArg value);
23 private delegate TResult StructGetDelegate<T, out TResult>(ref T obj);
25 private static readonly MethodInfo s_createGetterInternal = typeof(FastInvokerBuilder).GetMethod(nameof(CreateGetterInternal), BindingFlags.NonPublic | BindingFlags.Public | BindingFlags.Static)!;
26 private static readonly MethodInfo s_createSetterInternal = typeof(FastInvokerBuilder).GetMethod(nameof(CreateSetterInternal), BindingFlags.NonPublic | BindingFlags.Public | BindingFlags.Static)!;
27 private static readonly MethodInfo s_make = typeof(FastInvokerBuilder).GetMethod(nameof(Make), BindingFlags.NonPublic | BindingFlags.Public | BindingFlags.Static)!;
29 [RequiresDynamicCode(DataContract.SerializerAOTWarning)]
30 [UnconditionalSuppressMessage("ReflectionAnalysis", "IL2060:MakeGenericMethod",
31 Justification = "The call to MakeGenericMethod is safe due to the fact that we are preserving the constructors of type which is what Make() is doing.")]
32 public static Func<object> GetMakeNewInstanceFunc(
33 [DynamicallyAccessedMembers(DynamicallyAccessedMemberTypes.PublicParameterlessConstructor)]
36 Func<object> make = s_make.MakeGenericMethod(type).CreateDelegate<Func<object>>();
40 [UnconditionalSuppressMessage("ReflectionAnalysis", "IL2060:MakeGenericMethod",
41 Justification = "The call to MakeGenericMethod is safe due to the fact that FastInvokerBuilder.CreateGetterInternal<T, T1> is not annotated.")]
42 public static Getter CreateGetter(MemberInfo memberInfo)
44 if (memberInfo is PropertyInfo propInfo)
46 Type declaringType = propInfo.DeclaringType!;
47 Type propertyType = propInfo.PropertyType!;
49 if (declaringType.IsGenericType && declaringType.GetGenericTypeDefinition() == typeof(KeyValue<,>))
51 if (propInfo.Name == "Key")
55 return ((IKeyValue)obj).Key;
62 return ((IKeyValue)obj).Value;
67 // If either of the arguments to MakeGenericMethod is a valuetype, this is going to cause JITting.
68 // Only JIT if dynamic code is supported.
69 if (RuntimeFeature.IsDynamicCodeSupported || (!declaringType.IsValueType && !propertyType.IsValueType))
71 #pragma warning disable IL3050 // AOT compiling should recognize that this call is gated by RuntimeFeature.IsDynamicCodeSupported.
72 var createGetterGeneric = s_createGetterInternal.MakeGenericMethod(declaringType, propertyType).CreateDelegate<Func<PropertyInfo, Getter>>();
73 #pragma warning restore IL3050 // Calling members annotated with 'RequiresDynamicCodeAttribute' may break functionality when AOT compiling.
74 return createGetterGeneric(propInfo);
78 return propInfo.GetValue;
81 else if (memberInfo is FieldInfo fieldInfo)
85 var value = fieldInfo.GetValue(obj);
91 throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(new InvalidOperationException(SR.Format(SR.InvalidMember, DataContract.GetClrTypeFullName(memberInfo.DeclaringType!), memberInfo.Name)));
95 [UnconditionalSuppressMessage("ReflectionAnalysis", "IL2060:MakeGenericMethod",
96 Justification = "The call to MakeGenericMethod is safe due to the fact that FastInvokerBuilder.CreateSetterInternal<T, T1> is not annotated.")]
97 public static Setter CreateSetter(MemberInfo memberInfo)
99 if (memberInfo is PropertyInfo propInfo)
101 if (propInfo.CanWrite)
103 Type declaringType = propInfo.DeclaringType!;
104 Type propertyType = propInfo.PropertyType!;
106 if (declaringType.IsGenericType && declaringType.GetGenericTypeDefinition() == typeof(KeyValue<,>))
108 if (propInfo.Name == "Key")
110 return (ref object obj, object? val) =>
112 ((IKeyValue)obj).Key = val;
117 return (ref object obj, object? val) =>
119 ((IKeyValue)obj).Value = val;
124 // If either of the arguments to MakeGenericMethod is a valuetype, this is going to cause JITting.
125 // Only JIT if dynamic code is supported.
126 if (RuntimeFeature.IsDynamicCodeSupported || (!declaringType.IsValueType && !propertyType.IsValueType))
128 #pragma warning disable IL3050 // AOT compiling should recognize that this call is gated by RuntimeFeature.IsDynamicCodeSupported.
129 var createSetterGeneric = s_createSetterInternal.MakeGenericMethod(propInfo.DeclaringType!, propInfo.PropertyType).CreateDelegate<Func<PropertyInfo, Setter>>();
130 #pragma warning restore IL3050 // Calling members annotated with 'RequiresDynamicCodeAttribute' may break functionality when AOT compiling.
131 return createSetterGeneric(propInfo);
135 return (ref object obj, object? val) =>
137 propInfo.SetValue(obj, val);
143 throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(new InvalidOperationException(SR.Format(SR.NoSetMethodForProperty, propInfo.DeclaringType, propInfo.Name)));
146 else if (memberInfo is FieldInfo fieldInfo)
148 return (ref object obj, object? val) =>
150 fieldInfo.SetValue(obj, val);
155 throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(new InvalidOperationException(SR.Format(SR.InvalidMember, DataContract.GetClrTypeFullName(memberInfo.DeclaringType!), memberInfo.Name)));
159 private static object Make<T>() where T : new()
165 private static Getter CreateGetterInternal<DeclaringType, PropertyType>(PropertyInfo propInfo)
167 if (typeof(DeclaringType).IsValueType)
169 var getMethod = propInfo.GetMethod!.CreateDelegate<StructGetDelegate<DeclaringType, PropertyType>>();
173 var unboxed = (DeclaringType)obj;
174 return getMethod(ref unboxed);
179 var getMethod = propInfo.GetMethod!.CreateDelegate<Func<DeclaringType, PropertyType>>();
183 return getMethod((DeclaringType)obj);
188 private static Setter CreateSetterInternal<DeclaringType, PropertyType>(PropertyInfo propInfo)
190 if (typeof(DeclaringType).IsValueType)
192 var setMethod = propInfo.SetMethod!.CreateDelegate<StructSetDelegate<DeclaringType, PropertyType>>();
194 return (ref object obj, object? val) =>
196 var unboxed = (DeclaringType)obj;
197 setMethod(ref unboxed, (PropertyType)val!);
203 var setMethod = propInfo.SetMethod!.CreateDelegate<Action<DeclaringType, PropertyType>>();
205 return (ref object obj, object? val) =>
207 setMethod((DeclaringType)obj, (PropertyType)val!);