Ejemplo n.º 1
0
        static void ImplementInterface(Type interfaceType, TypeBuilder builder, FieldBuilder channel)
        {
            if (builder.FindInterfaces((t, o) => t == interfaceType, null).Length == 0)
            {
                builder.AddInterfaceImplementation(interfaceType);

                var parentInterfaces = interfaceType.GetInterfaces();
                foreach (var _interface in parentInterfaces)
                {
                    ImplementInterface(_interface, builder, channel);
                }

                IEnumerable <OperationDescription> operations = null;
                var intInfo = interfaceType.GetTypeInfo();

                if (ContractDescription.IsContract(intInfo))
                {
                    operations = ContractDescription.ValidateContract(intInfo);
                }
                else
                {
                    operations = interfaceType.GetMethods().Select(x => new OperationDescription(x));
                }

                foreach (var operation in operations)
                {
                    var mb = builder.DefineMethod(
                        $"{interfaceType.Name}.{operation.Name}",
                        MethodAttributes.Public | MethodAttributes.Virtual,
                        operation.ReturnType,
                        operation.ParameterTypes);

                    var il = mb.GetILGenerator();

                    il.Emit(OpCodes.Ldarg_0);
                    il.Emit(OpCodes.Ldfld, channel);

                    MethodInfo invoke = null;
                    //implement the user interface
                    if (operation.IsOperation)
                    {
                        if (operation.IsOneWay)
                        {
                            invoke = ImplementingType.GetMethod("SendOneWay");
                        }
                        else if (operation.IsVoidTask)
                        {
                            invoke = ImplementingType.GetMethod("SendVoid");
                        }
                        else
                        {
                            invoke = ImplementingType.GetMethod("SendReturn")
                                     .MakeGenericMethod(operation.ReturnType.GetGenericArguments()
                                                        .First());
                        }

                        il.Emit(OpCodes.Ldstr, mb.Name);
                        il.Emit(OpCodes.Ldc_I4_S, operation.ParameterTypes.Length);
                        il.Emit(OpCodes.Newarr, typeof(object));
                        for (byte x = 0; x < operation.ParameterTypes.Length; x++)
                        {
                            var xType = operation.ParameterTypes[x];
                            il.Emit(OpCodes.Dup);
                            il.Emit(OpCodes.Ldc_I4_S, x);
                            switch (x)
                            {
                            case 0: il.Emit(OpCodes.Ldarg_1); break;

                            case 1: il.Emit(OpCodes.Ldarg_2); break;

                            case 2: il.Emit(OpCodes.Ldarg_3); break;

                            default: il.Emit(OpCodes.Ldarg_S, x + 1); break;
                            }
                            if (xType.GetTypeInfo().IsValueType)
                            {
                                il.Emit(OpCodes.Box, xType);
                            }
                            il.Emit(OpCodes.Stelem_Ref);
                        }
                    }
                    else
                    {
                        invoke = ImplementingType.GetMethod(operation.Name, operation.ParameterTypes);
                        for (byte x = 0; x < operation.ParameterTypes.Length; x++)
                        {
                            switch (x)
                            {
                            case 0: il.Emit(OpCodes.Ldarg_1); break;

                            case 1: il.Emit(OpCodes.Ldarg_2); break;

                            case 2: il.Emit(OpCodes.Ldarg_3); break;

                            default: il.Emit(OpCodes.Ldarg_S, x + 1); break;
                            }
                        }
                    }
                    il.Emit(OpCodes.Call, invoke);
                    il.Emit(OpCodes.Ret);

                    builder.DefineMethodOverride(mb, operation.MethodInfo);
                }
            }
        }