Ejemplo n.º 1
0
        static private FieldDefinition Intermediate(this MethodDefinition method, MethodDefinition authentic, int neptuneMethodIndex)
        {
            var _intermediate = method.DeclaringType.Authority("<Intermediate>").Type(method.IsConstructor ? $"<<Constructor>>" : $"<{method.Name}>", TypeAttributes.NestedPublic | TypeAttributes.Class | TypeAttributes.Abstract | TypeAttributes.Sealed | TypeAttributes.BeforeFieldInit);

            foreach (var _parameter in method.GenericParameters)
            {
                _intermediate.GenericParameters.Add(new GenericParameter(_parameter.Name, _intermediate));
            }
            var                 _field                = _intermediate.Field <IntPtr>(Program.Pointer, FieldAttributes.Static | FieldAttributes.Public);
            FieldReference      _fieldReference       = _field;
            MethodReference     _authenticReference   = authentic;
            GenericInstanceType _authenticGenericType = null;

            if (_intermediate.HasGenericParameters)
            {
                _intermediate.Field("<NeptuneMethodIndex>", FieldAttributes.Public, neptuneMethodIndex);
                var _intermediateGenericType = _intermediate.MakeGenericType(_intermediate.GenericParameters);
                _fieldReference = _intermediateGenericType.Reference(_fieldReference);
                if (method.DeclaringType.HasGenericParameters)
                {
                    var _typeParameters   = _intermediate.GenericParameters.Take(method.DeclaringType.GenericParameters.Count).ToArray();
                    var _methodParameters = _intermediate.GenericParameters.Skip(method.DeclaringType.GenericParameters.Count).ToArray();
                    _authenticGenericType = authentic.DeclaringType.MakeGenericType(_typeParameters);
                    _authenticReference   = _authenticGenericType.Reference(authentic, _intermediate.GenericParameters);
                }
                else if (method.HasGenericParameters)
                {
                    _authenticReference = authentic.MakeGenericMethod(_intermediate.GenericParameters);
                }
            }
            var _initializer = _intermediate.Initializer();
            var _variable    = _initializer.Body.Variable <RuntimeMethodHandle>();

            _initializer.Body.Variable <Func <IntPtr> >();
            // todo Jens fix generic method in generic type to us ldtoken
            if (method.DeclaringType.HasGenericParameters && method.HasGenericParameters)
            {
                // work around for ldtoken _authenticReference not working correctly for generic method in generic type
                var methodInstantiatingMethodReference = _initializer.Module.Import(typeof(CNeptuneBase.InstantiationListener).GetMethod(nameof(CNeptuneBase.InstantiationListener.MethodInstantiating)));
                var _intermediateReference             = _intermediate.MakeGenericType(_intermediate.GenericParameters);
                _initializer.Body.Emit(OpCodes.Ldtoken, _intermediateReference);
                _initializer.Body.Emit(OpCodes.Ldtoken, _authenticGenericType);
                _initializer.Body.Emit(OpCodes.Call, _initializer.DeclaringType.Module.Import(Program.GetTypeFromHandle));
                _initializer.Body.Emit(OpCodes.Call, _initializer.DeclaringType.Module.Import(methodInstantiatingMethodReference));
            }
            else
            {
                _initializer.Body.Emit(_authenticReference);
            }
            _initializer.Body.Emit(OpCodes.Callvirt, Program.GetMethodHandle);
            _initializer.Body.Emit(OpCodes.Stloc_0);
            _initializer.Body.Emit(OpCodes.Ldloca_S, _variable);
            _initializer.Body.Emit(OpCodes.Callvirt, Program.GetFunctionPointer);
            _initializer.Body.Emit(OpCodes.Stsfld, _fieldReference);
            if (_intermediate.HasGenericParameters)
            {
                var methodInstantiatedMethodReference = _initializer.Module.Import(typeof(CNeptuneBase.InstantiationListener).GetMethod(nameof(CNeptuneBase.InstantiationListener.MethodInstantiated)));
                var _intermediateReference            = _intermediate.MakeGenericType(_intermediate.GenericParameters);
                _initializer.Body.Emit(OpCodes.Ldtoken, _intermediateReference);
                _initializer.Body.Emit(OpCodes.Call, _initializer.DeclaringType.Module.Import(Program.GetTypeFromHandle));
                _initializer.Body.Emit(OpCodes.Call, _initializer.DeclaringType.Module.Import(methodInstantiatedMethodReference));
            }

            //TODO : IOC of AOP !? What the? in fact it will be used to be able to inject on method on demand but a late as possible.
            //Action<MethodBase> _update;
            //lock (AppDomain.CurrentDomain.Evidence.SyncRoot) { _update = AppDomain.CurrentDomain.GetData("<Neptune<Update>>") as Action<MethodBase>; }
            //if (_update != null) { _update(...); }
            _initializer.Body.Emit(OpCodes.Ret);
            _initializer.Body.OptimizeMacros();
            return(_field);
        }