/// <summary> /// Generates the type. /// </summary> /// <param name="baseType">The base type being ducked.</param> /// <param name="duckTypes">The duck type interfaces.</param> /// <param name="serviceProvider">The current dependency scope.</param> /// <returns>A duck type.</returns> private Type GenerateType(Type baseType, Type[] duckTypes, IServiceProvider serviceProvider) { var typeBuilder = TypeFactory .Default .NewType(TypeName(baseType, duckTypes)) .Public() .Class() .Implements <IDuckTypedObject>() .ImplementsInterfaces(duckTypes); var baseTypeField = typeBuilder .NewField("target", baseType) .Private(); var serviceProviderField = typeBuilder .NewField <IServiceProvider>("serviceProvider") .Private(); foreach (Type duckType in duckTypes) { var context = new TypeFactoryContext(typeBuilder, duckType, baseType, serviceProvider, baseTypeField, serviceProviderField); this.ImplementInterfaces(context); } // Implement the IDuckTypedObject interface. this.ImplementDuckTypedObjectInterface(typeBuilder, baseTypeField); // Add a constructor to the type. this.AddConstructor(typeBuilder, baseType, baseTypeField, serviceProviderField); // Create the type. return(typeBuilder.CreateType()); }
/// <summary> /// Creates a new <see cref="TypeFactoryContext"/> instance for a new interface type. /// </summary> /// <param name="interfaceType">The duck <see cref="Type"/>.</param> /// <returns>The new <see cref="TypeFactoryContext"/> instance.</returns> public TypeFactoryContext CreateTypeFactoryContext(Type interfaceType) { var context = new TypeFactoryContext(this.TypeBuilder, interfaceType, this.BaseTypes, this.ServiceProvider, this.BaseObjectField, this.ServiceProviderField, this.ConstructorBuilder); return(context); }
private void ImplementInterfaces(TypeFactoryContext context) { var propertyMethods = new Dictionary <string, IMethodBuilder>(); foreach (var memberInfo in context.NewType.GetMembers()) { if (memberInfo.MemberType == MemberTypes.Method) { MethodInfo methodInfo = (MethodInfo)memberInfo; Type[] methodArgs = methodInfo .GetParameters().Select(p => p.ParameterType).ToArray(); if (methodInfo.ContainsGenericParameters == true) { Type[] genericArguments = methodInfo.GetGenericArguments(); var methodBuilder = context .TypeBuilder .NewMethod(methodInfo.Name) .Public() .Virtual() .Params(methodArgs) .Returns(methodInfo.ReturnType); methodBuilder .NewGenericParameters( genericArguments.Select(t => t.Name).ToArray(), (gps) => { for (int m = 0; m < gps.Length; m++) { gps[m].Attributes = genericArguments[m].GenericParameterAttributes; } }); /* * GenericTypeParameterBuilder[] genericTypeParameterBuilder = methodBuilder * .DefineGenericParameters( * genericArguments * .Select(t => t.Name) * .ToArray()); * * for (int m = 0; m < genericTypeParameterBuilder.Length; m++) * { * genericTypeParameterBuilder[m].SetGenericParameterAttributes(genericArguments[m].GetTypeInfo().GenericParameterAttributes); * } */ var methodIL = methodBuilder.Body(); if (context.BaseType.GetMethod(methodInfo.Name, methodInfo.GetGenericArguments()) == null) { // Throw NotImplementedException methodIL.ThrowException(typeof(NotImplementedException)); continue; } ILocal methodReturn = null; if (methodInfo.ReturnType != typeof(void)) { methodIL.DeclareLocal(methodInfo.ReturnType, out methodReturn); } methodIL .LdArg0() .LdFld(context.BaseObjectField) .EmitLoadParameters(methodInfo); MethodInfo callMethod1 = context.BaseObjectField.FieldType.GetMethod(memberInfo.Name, genericArguments); MethodInfo callMethod = context.BaseObjectField.FieldType.GetMethod(memberInfo.Name, methodArgs).MakeGenericMethod(genericArguments); methodIL .CallVirt(callMethod1); if (methodReturn != null) { methodIL .StLoc(methodReturn) .LdLoc(methodReturn); } methodIL.Ret(); } else { MethodAttributes attrs = methodInfo.Attributes & ~MethodAttributes.Abstract; var methodBuilder = context .TypeBuilder .NewMethod( methodInfo.Name, attrs, CallingConventions.HasThis, methodInfo.ReturnType) .Params(methodArgs); var methodIL = methodBuilder.Body(); if (context.BaseType.GetMethod(methodInfo.Name, methodArgs) == null) { // Throw NotImplementedException methodIL.ThrowException(typeof(NotImplementedException)); continue; } ILocal methodReturn = null; if (methodInfo.ReturnType != typeof(void)) { methodIL.DeclareLocal(methodInfo.ReturnType, out methodReturn); } methodIL .LdArg0() .LdFld(context.BaseObjectField) .EmitLoadParameters(methodInfo); MethodInfo callMethod = context.BaseObjectField.FieldType.GetMethod(memberInfo.Name, methodArgs); methodIL .CallVirt(callMethod); if (methodReturn != null) { methodIL .StLoc(methodReturn) .LdLoc(methodReturn); } methodIL.Ret(); if (methodInfo.IsProperty() == true) { propertyMethods.Add(methodInfo.Name, methodBuilder); } } } else if (memberInfo.MemberType == MemberTypes.Property) { var propertyBuilder = context .TypeBuilder .NewProperty( memberInfo.Name, ((PropertyInfo)memberInfo).PropertyType) .Attributes(PropertyAttributes.SpecialName); if (propertyMethods.TryGetValue(memberInfo.PropertyGetName(), out IMethodBuilder getMethod) == true) { propertyBuilder.GetMethod = getMethod; } if (propertyMethods.TryGetValue(memberInfo.PropertySetName(), out IMethodBuilder setMethod) == true) { propertyBuilder.SetMethod = setMethod; } } } }