예제 #1
0
        /// <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());
        }
예제 #2
0
        /// <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);
        }
예제 #3
0
        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;
                    }
                }
            }
        }