public virtual void GenerateMethod(PropertyInfo pi, MethodInfo mi, ILGenerator gen)
        {
            // Set default values for out parameters
            foreach (var par in mi.GetParameters().Where(p => p.IsOut))
            {
                var defaultAttr = par.GetCustomAttributes(typeof(SafeDefaultAttribute), true)
                    .Cast<SafeDefaultAttribute>().FirstOrDefault();

                var type = par.ParameterType.GetElementType();
                gen.EmitBestLdArg((ushort)(par.Position + 1));
                if (defaultAttr!=null)
                    defaultAttr.PushValueAction(gen);
                else
                    PushDefaultReturnValue(gen, type);
                gen.EmitStoreToRef(type);
            }

            // Set default value for return types
            if (mi.ReturnType!=typeof(void))
            {
                MemberInfo attrSource = mi;
                if (pi!=null)
                    attrSource = pi;

                var defaultAttr = attrSource.GetCustomAttributes(typeof(SafeDefaultAttribute), true)
                    .Cast<SafeDefaultAttribute>().FirstOrDefault();
                if (defaultAttr!=null)
                    defaultAttr.PushValueAction(gen);
                else
                    PushDefaultReturnValue(gen, mi.ReturnType);
            }
            gen.Emit(OpCodes.Ret);
        }
 public virtual void GenerateMethod(PropertyInfo pi, MethodInfo mi, ILGenerator gen)
 {
     _rsmc.PutRealSubjectOnStack(gen);
     var pars = mi.GetParameters();
     for (ushort i = 1; i <= pars.Length; ++i)
         gen.EmitBestLdArg(i);
     gen.Emit(OpCodes.Callvirt, mi);
     gen.Emit(OpCodes.Ret);
 }
예제 #3
0
        public override void GenerateCall(IProxyModuleCoderAccess proxyModule, ILGenerator gen)
        {
            var pars = _adaptee.GetParameters();
            var targetPars = _target.GetParameters();

            var tokens = new object[pars.Length];

            // Generate in conversions
            for (ushort i = 0; i < pars.Length; ++i)
            {
                // ReSharper disable once AccessToModifiedClosure
                tokens[i] = _paramBindings[i].GenerateInConversion(() => gen.EmitBestLdArg((ushort)(i + 1)), proxyModule, gen);
            }

            gen.Emit(OpCodes.Callvirt, _target);

            // Generate out conversions
            for (ushort i = 0; i < pars.Length; ++i)
            {
                // ReSharper disable once AccessToModifiedClosure
                _paramBindings[i].GenerateOutConversion(tokens[i], () => gen.EmitBestLdArg((ushort)(i + 1)), proxyModule, gen);
            }

            _retValBinding.GenerateConversion(proxyModule, gen);
        }
        public virtual void GenerateMethod(PropertyInfo pi, MethodInfo mi, ILGenerator gen)
        {
            var smeType = typeof(ISubjectMethodExists<>).MakeGenericType(_subjectType);
            var getSmeMethod = typeof(IMethodExistsProxyMeta).GetMethod("GetSubjectMethodExists").MakeGenericMethod(new[] {_subjectType});
            var dmeMethod = smeType.GetMethod("DoesMethodExist", new[] {typeof(int)});

            // Locals
            var methodExistsProxyMetaLocal = gen.DeclareLocal(typeof(IMethodExistsProxyMeta));
            var subjectMethodExistsLocal = gen.DeclareLocal(smeType);
            var makingSafeCallLocal = gen.DeclareLocal(typeof(bool));

            // Labels
            var callOnRealSubjectLabel = gen.DefineLabel();
            var makeInnerSubjectCall = gen.DefineLabel();
            var retLabel = gen.DefineLabel();

            // Check to see if the real subject supports method exists testing
            _rsmc.PutRealSubjectOnStack(gen);
            gen.Emit(OpCodes.Isinst, typeof(IMethodExistsProxyMeta));
            gen.Emit(OpCodes.Dup);
            gen.Emit(OpCodes.Stloc, methodExistsProxyMetaLocal);
            gen.Emit(OpCodes.Brfalse, callOnRealSubjectLabel);
            gen.Emit(OpCodes.Ldloc, methodExistsProxyMetaLocal);

            // It does - see if this method exists
            gen.Emit(OpCodes.Callvirt, getSmeMethod);
            gen.Emit(OpCodes.Dup);
            gen.Emit(OpCodes.Stloc, subjectMethodExistsLocal);
            gen.Emit(OpCodes.Brfalse_S, callOnRealSubjectLabel);
            gen.Emit(OpCodes.Ldloc, subjectMethodExistsLocal);
            gen.Emit(OpCodes.Ldc_I4, _methodIndex);
            gen.Emit(OpCodes.Callvirt, dmeMethod);
            gen.Emit(OpCodes.Ldc_I4_0);
            gen.Emit(OpCodes.Ceq, 0);
            gen.Emit(OpCodes.Stloc, makingSafeCallLocal);
            gen.Emit(OpCodes.Ldloc, makingSafeCallLocal);
            gen.Emit(OpCodes.Brfalse_S, callOnRealSubjectLabel);
            EmitCtorForSafeNullProxy(gen, _subjectType);
            gen.Emit(OpCodes.Br_S, makeInnerSubjectCall);

            // Prepare to call on the real subject
            gen.MarkLabel(callOnRealSubjectLabel);
            _rsmc.PutRealSubjectOnStack(gen);

            // Push arguments & call method on the inner subject (real or null proxy)
            gen.MarkLabel(makeInnerSubjectCall);
            var pars = mi.GetParameters();
            for (ushort i = 1; i <= pars.Length; ++i)
                gen.EmitBestLdArg(i);
            gen.Emit(OpCodes.Callvirt, mi);

            // If the method does not exist then the result is already safe and we can return
            gen.Emit(OpCodes.Ldloc, makingSafeCallLocal);
            gen.Emit(OpCodes.Brtrue_S, retLabel);

            // If the return type needs to be made safe then do so
            if (mi.ReturnType!=typeof(void) && mi.ReturnType.IsInterface)
            {
                var notNullLabel = gen.DefineLabel();
                gen.Emit(OpCodes.Dup); // duplicate the return value on the stack
                gen.Emit(OpCodes.Brtrue_S, notNullLabel); // check it for null
                gen.Emit(OpCodes.Pop); // We don't need it - it's always null
                EmitCtorForSafeNullProxy(gen, mi.ReturnType);
                gen.Emit(OpCodes.Br_S, retLabel);
                gen.MarkLabel(notNullLabel);
                EmitCtorForSafeDirectProxy(gen, mi.ReturnType);
            }

            // Return
            gen.MarkLabel(retLabel);
            gen.Emit(OpCodes.Ret);

            ++_methodIndex;
        }