protected virtual Func <object, object[], object> CreateInvoker()
        {
            DynamicMethod dynamicMethod = new DynamicMethod($"invoker_{_displayName}",
                                                            typeof(object), new Type[] { typeof(object), typeof(object[]) }, _reflectionInfo.Module, true);

            ILGenerator ilGen          = dynamicMethod.GetILGenerator();
            var         parameterTypes = _reflectionInfo.GetParameterTypes();

            ilGen.EmitLoadArg(0);
            ilGen.EmitConvertFromObject(_reflectionInfo.DeclaringType);

            if (parameterTypes.Length == 0)
            {
                return(CreateDelegate());
            }

            var refParameterCount = parameterTypes.Count(x => x.IsByRef);

            if (refParameterCount == 0)
            {
                for (var i = 0; i < parameterTypes.Length; i++)
                {
                    ilGen.EmitLoadArg(1);
                    ilGen.EmitInt(i);
                    ilGen.Emit(OpCodes.Ldelem_Ref);
                    ilGen.EmitConvertFromObject(parameterTypes[i]);
                }
                return(CreateDelegate());
            }

            var indexedLocals = new IndexedLocalBuilder[refParameterCount];
            var index         = 0;

            for (var i = 0; i < parameterTypes.Length; i++)
            {
                ilGen.EmitLoadArg(1);
                ilGen.EmitInt(i);
                ilGen.Emit(OpCodes.Ldelem_Ref);
                if (parameterTypes[i].IsByRef)
                {
                    var defType      = parameterTypes[i].GetElementType();
                    var indexedLocal = new IndexedLocalBuilder(ilGen.DeclareLocal(defType), i);
                    indexedLocals[index++] = indexedLocal;
                    ilGen.EmitConvertFromObject(defType);
                    ilGen.Emit(OpCodes.Stloc, indexedLocal.LocalBuilder);
                    ilGen.Emit(OpCodes.Ldloca, indexedLocal.LocalBuilder);
                }
                else
                {
                    ilGen.EmitConvertFromObject(parameterTypes[i]);
                }
            }

            return(CreateDelegate(() =>
            {
                for (var i = 0; i < indexedLocals.Length; i++)
                {
                    ilGen.EmitLoadArg(1);
                    ilGen.EmitInt(indexedLocals[i].Index);
                    ilGen.Emit(OpCodes.Ldloc, indexedLocals[i].LocalBuilder);
                    ilGen.EmitConvertToObject(indexedLocals[i].LocalType);
                    ilGen.Emit(OpCodes.Stelem_Ref);
                }
            }));

            Func <object, object[], object> CreateDelegate(Action callback = null)
            {
                ilGen.EmitCall(OpCodes.Callvirt, _reflectionInfo, null);
                callback?.Invoke();
                if (_reflectionInfo.ReturnType == typeof(void))
                {
                    ilGen.Emit(OpCodes.Ldnull);
                }
                else if (_reflectionInfo.ReturnType.GetTypeInfo().IsValueType)
                {
                    ilGen.EmitConvertToObject(_reflectionInfo.ReturnType);
                }
                ilGen.Emit(OpCodes.Ret);
                return((Func <object, object[], object>)dynamicMethod.CreateDelegate(typeof(Func <object, object[], object>)));
            }
        }
Ejemplo n.º 2
0
        private Func <object[], object> CreateInvoker()
        {
            var dynamicMethod = new DynamicMethod($"invoker-{Guid.NewGuid()}", typeof(object), new Type[] { typeof(object[]) }, Member.Module, true);
            var ilGen         = dynamicMethod.GetILGenerator();

            if (Parameters.Length == 0)
            {
                ilGen.Emit(OpCodes.Newobj, Member);
                return(CreateDelegate());
            }
            var parameterTypes    = Parameters.Select(i => i.Member.ParameterType).ToArray();
            var refParameterCount = parameterTypes.Count(x => x.IsByRef);

            if (refParameterCount == 0)
            {
                for (var i = 0; i < parameterTypes.Length; i++)
                {
                    ilGen.EmitLoadArg(0);
                    ilGen.EmitInt(i);
                    ilGen.Emit(OpCodes.Ldelem_Ref);
                    ilGen.EmitConvertFromObject(parameterTypes[i]);
                }
                ilGen.Emit(OpCodes.Newobj, Member);
                return(CreateDelegate());
            }
            var indexedLocals = new IndexedLocalBuilder[refParameterCount];
            var index         = 0;

            for (var i = 0; i < parameterTypes.Length; i++)
            {
                ilGen.EmitLoadArg(0);
                ilGen.EmitInt(i);
                ilGen.Emit(OpCodes.Ldelem_Ref);
                if (parameterTypes[i].IsByRef)
                {
                    var defType      = parameterTypes[i].GetElementType();
                    var indexedLocal = new IndexedLocalBuilder(ilGen.DeclareLocal(defType), i);
                    indexedLocals[index++] = indexedLocal;
                    ilGen.EmitConvertFromObject(defType);
                    ilGen.Emit(OpCodes.Stloc, indexedLocal.LocalBuilder);
                    ilGen.Emit(OpCodes.Ldloca, indexedLocal.LocalBuilder);
                }
                else
                {
                    ilGen.EmitConvertFromObject(parameterTypes[i]);
                }
            }
            ilGen.Emit(OpCodes.Newobj, Member);
            for (var i = 0; i < indexedLocals.Length; i++)
            {
                ilGen.EmitLoadArg(0);
                ilGen.EmitInt(indexedLocals[i].Index);
                ilGen.Emit(OpCodes.Ldloc, indexedLocals[i].LocalBuilder);
                ilGen.EmitConvertToObject(indexedLocals[i].LocalType);
                ilGen.Emit(OpCodes.Stelem_Ref);
            }
            return(CreateDelegate());

            Func <object[], object> CreateDelegate()
            {
                if (Member.DeclaringType.GetTypeInfo().IsValueType)
                {
                    ilGen.EmitConvertToObject(Member.DeclaringType);
                }

                ilGen.Emit(OpCodes.Ret);
                return((Func <object[], object>)dynamicMethod.CreateDelegate(typeof(Func <object[], object>)));
            }
        }