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)); } }
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 }