private static void BuildFunc(CacheMethod method, ILGenerator il, Type keyType, Type valueType)
        {
            Type funcType;

            if (method.Method.IsAbstract)
            {
                Ldarg(il, method.Value + 1);

                funcType = method.Method.GetParameters()[method.Value].ParameterType;
            }
            else
            {
                il.Emit(OpCodes.Ldarg_0);
                il.Emit(OpCodes.Ldftn, method.Method);

                var result = method.Method.GetParameters().Select(p => p.ParameterType).Union(new[] { valueType }).ToArray();
                funcType = result.Length switch
                {
                    1 => typeof(Func <>).MakeGenericType(result),
                    2 => typeof(Func <,>).MakeGenericType(result),
                    3 => typeof(Func <, ,>).MakeGenericType(result),
                    4 => typeof(Func <, , ,>).MakeGenericType(result),
                    _ => throw CacheTypeResolver.ParameterException(method.Method.DeclaringType, method.Method)
                };

                il.Emit(OpCodes.Newobj, funcType.GetConstructors()[0]);
            }

            var args = funcType.GetGenericArguments();

            Type?arg1 = null, arg2 = null, arg3 = null, returnArg = null;

            if (args.Length > 1)
            {
                arg1 = args[0] == keyType ? typeof(object) : args[0];
            }
            if (args.Length > 2)
            {
                arg2 = args[1] == keyType ? typeof(object) : args[1];
            }
            if (args.Length > 3)
            {
                arg3 = args[2] == keyType ? typeof(object) : args[2];
            }
            if (args.Length > 4)
            {
                throw CacheTypeResolver.ParameterException(method.Method.DeclaringType, method.Method);
            }

            if (args[args.Length - 1].IsGenericType)
            {
                var type = args[args.Length - 1].GetGenericTypeDefinition();

                if (type == typeof(Task <>) || type == typeof(ValueTask <>))
                {
                    returnArg = type;
                }
            }

            if (arg1 != typeof(object) || arg2 != typeof(TimeSpan) || arg3 != typeof(CancellationToken) || method.AsyncType != null && returnArg != typeof(ValueTask <>))
            {
                il.Emit(OpCodes.Call, (method.AsyncType == null
                        ? FuncHelper.GetWrapMethod(arg1, arg2, arg3, returnArg)
                        : FuncHelper.GetWrapAsyncMethod(arg1, arg2, arg3, returnArg))
                        .MakeGenericMethod(keyType, method.ValueType));
            }
        }
Exemple #2
0
        private void BuildFunc(CacheMethod method, ILGenerator il, Type keyType, Type valueType)
        {
#if BuildTask
            GenericInstanceType funcType;
            if (method.Method.Resolve().IsAbstract)
#else
            Type funcType;
            if (method.Method.IsAbstract)
#endif
            {
                Ldarg(il, method.Value + 1);
#if BuildTask
                funcType = (GenericInstanceType)method.Method.GetParameters()[method.Value].ParameterType;
#else
                funcType = method.Method.GetParameters()[method.Value].ParameterType;
#endif
            }
            else
            {
                il.Emit(OpCodes.Ldarg_0);
                il.Emit(OpCodes.Ldftn, method.Method);

                var result = method.Method.GetParameters().Select(p => p.ParameterType).Union(new[] { valueType }).ToArray();
                funcType = result.Length switch
                {
#if BuildTask
                    1 => new GenericInstanceType(ImportType(typeof(Func <>))),
                    2 => new GenericInstanceType(ImportType(typeof(Func <,>))),
                    3 => new GenericInstanceType(ImportType(typeof(Func <, ,>))),
                    4 => new GenericInstanceType(ImportType(typeof(Func <, , ,>))),
#else
                    1 => typeof(Func <>).MakeGenericType(result),
                    2 => typeof(Func <,>).MakeGenericType(result),
                    3 => typeof(Func <, ,>).MakeGenericType(result),
                    4 => typeof(Func <, , ,>).MakeGenericType(result),
#endif
                    _ => throw CacheTypeResolver.ParameterException(method.Method.DeclaringType !, method.Method)
                };
#if BuildTask
                foreach (var p in result)
                {
                    funcType.GenericArguments.Add(p);
                }

                il.Emit(OpCodes.Newobj, Module.ImportReference(funcType.Resolve().GetConstructors().First()).CopyTo(funcType));
#else
                il.Emit(OpCodes.Newobj, funcType.GetConstructors()[0]);
#endif
            }

            var args = funcType.GetGenericArguments();

            Type?arg1 = null, arg2 = null, arg3 = null, returnArg = null;
#if BuildTask
            if (args.Length > 1)
            {
                arg1 = args[0] == keyType ? TypeSystem.Object : args[0];
            }
            if (args.Length > 2)
            {
                arg2 = args[1] == keyType ? TypeSystem.Object : args[1];
            }
            if (args.Length > 3)
            {
                arg3 = args[2] == keyType ? TypeSystem.Object : args[2];
            }
            if (args.Length > 4)
            {
                throw CacheTypeResolver.ParameterException(method.Method.DeclaringType !, method.Method);
            }

            if (args[args.Length - 1].IsGenericInstance)
            {
                var type = args[args.Length - 1].GetElementType();

                if (type.IsType(typeof(Task <>)) || type.IsType(typeof(ValueTask <>)))
                {
                    returnArg = type;
                }
            }

            if (arg1 != null && arg1.IsType <object>() &&
                arg2 != null && arg2.IsType <TimeSpan>() &&
                arg3 != null && arg3.IsType <CancellationToken>() &&
                (method.AsyncType == null || returnArg != null && returnArg.IsType(typeof(ValueTask <>))))
            {
                return;
            }

            var fat = _helper.FuncAdapterType.MakeGenericInstanceType(keyType, method.ValueType);

            il.Emit(OpCodes.Newobj, new MethodInfo(".ctor", TypeSystem.Void, fat)
            {
                Parameters = { new ParameterBuilder(TypeSystem.Object) }, HasThis = true
            });
            il.Emit(OpCodes.Ldftn, Module.ImportReference(_helper.GetWrapMethod(method.AsyncType == null, arg1, arg2, arg3, returnArg)).CopyTo(fat));
            il.Emit(OpCodes.Newobj, Module.ImportReference(typeof(Func <, , ,>).GetConstructors()[0]).CopyTo(ImportType(typeof(Func <, , ,>)).MakeGenericInstanceType(keyType.GetElementType(), ImportType <TimeSpan>(), ImportType <CancellationToken>(), method.AsyncType == null ? method.ValueType : ImportType(typeof(ValueTask <>)).MakeGenericInstanceType(method.ValueType.GetElementType()))));
#else
            if (args.Length > 1)
            {
                arg1 = args[0] == keyType ? typeof(object) : args[0];
            }
            if (args.Length > 2)
            {
                arg2 = args[1] == keyType ? typeof(object) : args[1];
            }
            if (args.Length > 3)
            {
                arg3 = args[2] == keyType ? typeof(object) : args[2];
            }
            if (args.Length > 4)
            {
                throw CacheTypeResolver.ParameterException(method.Method.DeclaringType !, method.Method);
            }

            if (args[args.Length - 1].IsGenericType)
            {
                var type = args[args.Length - 1].GetGenericTypeDefinition();

                if (type == typeof(Task <>) || type == typeof(ValueTask <>))
                {
                    returnArg = type;
                }
            }

            if (arg1 == typeof(object) && arg2 == typeof(TimeSpan) && arg3 == typeof(CancellationToken) &&
                (method.AsyncType == null || returnArg == typeof(ValueTask <>)))
            {
                return;
            }

            var fat = _helper.FuncAdapterType.MakeGenericType(keyType, method.ValueType);

            il.Emit(OpCodes.Newobj, fat.GetConstructors()[0]);
            il.Emit(OpCodes.Ldftn, fat.GetMethod(_helper.GetWrapMethod(method.AsyncType == null, arg1, arg2, arg3, returnArg).Name) !);
            il.Emit(OpCodes.Newobj, typeof(Func <, , ,>).MakeGenericType(keyType, typeof(TimeSpan), typeof(CancellationToken), method.AsyncType == null ? method.ValueType : typeof(ValueTask <>).MakeGenericType(method.ValueType)).GetConstructors()[0]);
#endif
        }