/// <summary> /// Implements a <see cref="ISpecializationCacheArgs"/> interface in order to /// make the given <paramref name="typeBuilder"/> compatible with a /// <see cref="SpecializationCache{TLoader, TArgs, TDelegate}"/> instance. /// </summary> /// <param name="typeBuilder">The target type builder to use.</param> /// <param name="fields">The source fields used for implementation.</param> private static void ImplementSpecializationCacheArgs( TypeBuilder typeBuilder, FieldInfo[] fields) { var specializedType = typeof(SpecializedValue <>); var getArgMethod = typeBuilder.DefineMethod( nameof(ISpecializationCacheArgs.GetSpecializedArg), MethodAttributes.Public | MethodAttributes.Virtual, typeof(object), new Type[] { typeof(int) }); var emitter = new ILEmitter(getArgMethod.GetILGenerator()); // Declare labels and emit jump table var labels = new ILLabel[fields.Length]; for (int i = 0, e = fields.Length; i < e; ++i) { labels[i] = emitter.DeclareLabel(); } emitter.Emit(OpCodes.Ldarg_1); emitter.EmitSwitch(labels); for (int i = 0, e = fields.Length; i < e; ++i) { var field = fields[i]; emitter.MarkLabel(labels[i]); emitter.Emit(OpCodes.Ldarg_0); emitter.Emit(OpCodes.Ldfld, field); // Wrap in a specialized instance var fieldReturnType = specializedType.MakeGenericType(field.FieldType); var instanceConstructor = fieldReturnType.GetConstructor( new Type[] { field.FieldType }); emitter.EmitNewObject(instanceConstructor); emitter.Emit(OpCodes.Box, fieldReturnType); emitter.Emit(OpCodes.Ret); } // Return dummy argument emitter.Emit(OpCodes.Ldnull); emitter.Emit(OpCodes.Ret); emitter.Finish(); typeBuilder.AddInterfaceImplementation(typeof(ISpecializationCacheArgs)); }