public static TInterface Implement <TInterface>(ILibrary library, Func <string, string> lookupFunctionName = null) where TInterface : class { if (library == null) { throw new ArgumentNullException("library"); } var mapper = new LibraryInterfaceMapper(new DelegateTypeBuilder(), new DefaultConstructorBuilder(lookupFunctionName), new DefaultMethodCallWrapper()); return(mapper.Implement <TInterface>(library)); }
public static TInterface Implement <TInterface>(ILibrary library, IMethodCallProbe <TInterface> probe, Func <string, string> lookupFunctionName = null) where TInterface : class { if (library == null) { throw new ArgumentNullException("library"); } if (probe == null) { throw new ArgumentNullException("probe"); } var constructorBuilder = new ProbingConstructorBuilder(lookupFunctionName); var methoCallWrapper = new ProbingMethodCallWrapper(() => constructorBuilder.ProbeField); var mapper = new LibraryInterfaceMapper(new DelegateTypeBuilder(), constructorBuilder, methoCallWrapper); return(mapper.Implement <TInterface>(library, probe)); }
/// <summary> /// Creates a <see cref="MethodBuilder"/> and implements a default wrapper. /// </summary> /// <param name="owner">The type that will own this method.</param> /// <param name="interfaceType">Type of interface implemented by the <paramref name="owner"/>.</param> /// <param name="overrideMethod">Method to override.</param> /// <param name="fieldBuilders">Fields specified by the <see paramref="owner"/>.</param> /// <returns>MethodBuilder with an already implemented wrapper.</returns> public MethodBuilder GenerateInvocation(TypeBuilder owner, Type interfaceType, MethodInfo overrideMethod, IEnumerable <FieldBuilder> fieldBuilders) { var result = owner.DefineMethod ( overrideMethod.Name, MethodAttributes.Private | MethodAttributes.Virtual | MethodAttributes.Final | MethodAttributes.HideBySig | MethodAttributes.NewSlot, overrideMethod.ReturnType, overrideMethod.GetParameters().OrderBy(p => p.Position).Select(t => t.ParameterType).ToArray() ); result.SetImplementationFlags(MethodImplAttributes.AggressiveInlining); var generator = result.GetILGenerator(); var fieldName = LibraryInterfaceMapper.GetFieldNameForMethodInfo(overrideMethod); var field = fieldBuilders.First(f => f.Name == fieldName); var parameters = overrideMethod.GetParameters(); OnInvokeBegin(owner, interfaceType, generator, overrideMethod); generator.Emit(OpCodes.Ldarg_0); // this generator.Emit(OpCodes.Ldfld, field); // MethodNameProc _glMethodName. Initialized by constructor. foreach (var item in parameters.Where(p => !p.IsRetval).Select((p, i) => new { Type = p, Index = i })) { generator.Emit(OpCodes.Ldarg, item.Index + 1); } generator.EmitCall(OpCodes.Callvirt, field.FieldType.GetMethod("Invoke"), null); OnInvokeEnd(owner, interfaceType, generator, overrideMethod); generator.Emit(OpCodes.Ret); owner.DefineMethodOverride(result, overrideMethod); return(result); }
/// <summary> /// Generates the constructor using the specified arguments. /// </summary> /// <param name="owner"></param> /// <param name="interfaceType"></param> /// <param name="methods"></param> /// <param name="fields"></param> /// <returns></returns> public ConstructorBuilder GenerateConstructor(TypeBuilder owner, Type interfaceType, IEnumerable <MethodInfo> methods, IEnumerable <FieldBuilder> fields) { var builder = DefineConstructor(owner, interfaceType); var generator = builder.GetILGenerator(); var notSupportedConstructor = typeof(MissingEntryPointException).GetConstructor( new[] { typeof(string), typeof(ILibrary) }); if (notSupportedConstructor == null) { throw new MissingMethodException("MissingEntryPointException", ".ctr(string, ILibrary)"); } var loc = generator.DeclareLocal(typeof(Delegate)); var fieldBuilders = fields as FieldBuilder[] ?? fields.ToArray(); EmitBegin(owner, interfaceType, generator); foreach (var method in methods) { generator.BeginScope(); var entryPoint = method.GetCustomAttributes(typeof(EntryPointAttribute), false).OfType <EntryPointAttribute>().FirstOrDefault(); string methodName; if (entryPoint != null) { methodName = entryPoint.Name; } else if (lookupFunctionName != null) { methodName = lookupFunctionName(method.Name); } else { var libAttrib = interfaceType.GetCustomAttributes(typeof(EntryPointFormatAttribute), false).OfType <EntryPointFormatAttribute>().FirstOrDefault(); if (libAttrib != null && !string.IsNullOrEmpty(libAttrib.Format)) { methodName = string.Format(libAttrib.Format, method.Name); } else { methodName = method.Name; } } var name = LibraryInterfaceMapper.GetFieldNameForMethodInfo(method); var field = fieldBuilders.Single(f => f.Name == name); var okLabel = generator.DefineLabel(); generator.Emit(OpCodes.Ldarg_1); // ILibrary generator.Emit(OpCodes.Ldstr, methodName); // load constant method name var getMethod = typeof(ILibrary).GetMethod("GetProcedure", new[] { typeof(string) }).MakeGenericMethod(field.FieldType); // lib.GetProcedure<Field.FieldType>(methodName) generator.EmitCall(OpCodes.Callvirt, getMethod, null); generator.Emit(OpCodes.Stloc, loc); // result = GetProcedure<DelegateType>(methodName); // if result == null throw MethodNotSupportedException generator.Emit(OpCodes.Ldloc, loc); generator.Emit(OpCodes.Brtrue_S, okLabel); // if(result != null) goto okLabel generator.Emit(OpCodes.Ldstr, methodName); generator.Emit(OpCodes.Ldarg_1); generator.Emit(OpCodes.Newobj, notSupportedConstructor); generator.Emit(OpCodes.Throw); // throw new MissingMethodException(methodName) generator.MarkLabel(okLabel); // Everything went okay. Set the delegate to the returned function. generator.Emit(OpCodes.Ldarg_0); // this generator.Emit(OpCodes.Ldloc, loc); // result generator.Emit(OpCodes.Stfld, field); // this._fieldName = result; generator.EndScope(); } EmitEnd(owner, interfaceType, generator); generator.Emit(OpCodes.Ret); return(builder); }
/// <summary> /// Creates a <see cref="MethodBuilder"/> and implements a default wrapper. /// </summary> /// <param name="owner">The type that will own this method.</param> /// <param name="interfaceType">Type of interface implemented by the <paramref name="owner"/>.</param> /// <param name="overrideMethod">Method to override.</param> /// <param name="fieldBuilders">Fields specified by the <see paramref="owner"/>.</param> /// <returns>MethodBuilder with an already implemented wrapper.</returns> public MethodBuilder GenerateInvocation(TypeBuilder owner, Type interfaceType, MethodInfo overrideMethod, IEnumerable <FieldBuilder> fieldBuilders) { Type[] MakeNullIfEmpty(Type[] input) { return(input.Length == 0 ? null : input); } Type[][] MakeNullIfEmptyArray(Type[][] input) { return(input.All(x => x == null) ? null : input); } var parameters = overrideMethod.GetParameters(); var parameterTypes = parameters.Select(t => t.ParameterType).ToArray(); var ret = overrideMethod.ReturnParameter; var parameterTypeRequiredCustomModifiers = MakeNullIfEmptyArray(parameters.Select(x => MakeNullIfEmpty(x.GetRequiredCustomModifiers())).ToArray()); var parameterTypeOptionalCustomModifiers = MakeNullIfEmptyArray(parameters.Select(x => MakeNullIfEmpty(x.GetOptionalCustomModifiers())).ToArray()); var returnTypeRequiredCustomModifiers = MakeNullIfEmpty(ret.GetRequiredCustomModifiers()); var returnTypeOptionalCustomModifiers = MakeNullIfEmpty(ret.GetOptionalCustomModifiers()); var result = owner.DefineMethod ( name: overrideMethod.Name, attributes: MethodAttributes.Private | MethodAttributes.Virtual | MethodAttributes.Final | MethodAttributes.HideBySig | MethodAttributes.NewSlot, callingConvention: overrideMethod.CallingConvention, returnType: overrideMethod.ReturnType, returnTypeRequiredCustomModifiers: returnTypeRequiredCustomModifiers, returnTypeOptionalCustomModifiers: returnTypeOptionalCustomModifiers, parameterTypes: parameterTypes, parameterTypeRequiredCustomModifiers: parameterTypeRequiredCustomModifiers, parameterTypeOptionalCustomModifiers: parameterTypeOptionalCustomModifiers ); #if !NET35 result.SetImplementationFlags(MethodImplAttributes.AggressiveInlining); #endif var generator = result.GetILGenerator(); var fieldName = LibraryInterfaceMapper.GetFieldNameForMethodInfo(overrideMethod); var field = fieldBuilders.First(f => f.Name == fieldName); OnInvokeBegin(owner, interfaceType, generator, overrideMethod); generator.Emit(OpCodes.Ldarg_0); // this generator.Emit(OpCodes.Ldfld, field); // MethodNameProc _glMethodName. Initialized by constructor. foreach (var item in parameters.Where(p => !p.IsRetval)) { generator.Emit(OpCodes.Ldarg, item.Position + 1); // 0 is `this` so we skip it } generator.EmitCall(OpCodes.Callvirt, field.FieldType.GetMethod("Invoke"), null); OnInvokeEnd(owner, interfaceType, generator, overrideMethod); generator.Emit(OpCodes.Ret); owner.DefineMethodOverride(result, overrideMethod); return(result); }