예제 #1
0
        /// <summary>
        /// Emits an implementation of a given method.
        /// </summary>
        /// <param name="invocationContext">The InvocationContext for this call.</param>
        /// <param name="eventId">The next eventID to use.</param>
        /// <param name="autoKeyword">The auto-keyword to use if enabled.</param>
        /// <returns>The method that is implemented.</returns>
        private MethodBuilder EmitMethodImpl(InvocationContext invocationContext, ref int eventId, EventKeywords autoKeyword)
        {
            // get the method we are implementing and the parameter mapping
            var interfaceMethod  = invocationContext.MethodInfo;
            var parameterMapping = _traceParameterProvider.ProvideParameterMapping(invocationContext.MethodInfo).Where(p => p.HasSource).ToList();

            // if we are implementing an interface, then add an string context parameter
            if (SupportsContext(invocationContext))
            {
                parameterMapping.Add(new ParameterMapping(Context));
            }

            // calculate the method name
            // if there is more than one method with the given name, then append an ID to it
            var methodName      = interfaceMethod.Name;
            var matchingMethods = interfaceMethod.DeclaringType.GetMethods().AsEnumerable().Where(im => String.Compare(im.Name, methodName, StringComparison.OrdinalIgnoreCase) == 0).ToArray();

            if (matchingMethods.Length > 1)
            {
                methodName += "_" + Array.IndexOf(matchingMethods, interfaceMethod).ToString(CultureInfo.InvariantCulture);
            }

            // determine if this is a non-event or an event
            // if an event, but there is no event attribute, just add one to the last event id
            EventAttribute eventAttribute = null;

            if (interfaceMethod.GetCustomAttribute <NonEventAttribute>() == null)
            {
                eventAttribute = _eventAttributeProvider.GetEventAttribute(invocationContext, eventId);
                eventId        = Math.Max(eventId, eventAttribute.EventId + 1);
            }

            // if auto-keywords are enabled, use them
            if (eventAttribute != null && eventAttribute.Keywords == EventKeywords.None)
            {
                eventAttribute.Keywords = autoKeyword;
            }

            // create the internal method that calls WriteEvent
            // this cannot be virtual or static, or the manifest builder will skip it
            // it also cannot return a value
            MethodBuilder m = _typeBuilder.DefineMethod(methodName, MethodAttributes.Public, typeof(void), parameterMapping.Select(p => p.CleanTargetType).ToArray());

            // copy the Event or NonEvent attribute from the interface
            if (eventAttribute != null)
            {
                m.SetCustomAttribute(EventAttributeHelper.ConvertEventAttributeToAttributeBuilder(eventAttribute));
            }
            else
            {
                m.SetCustomAttribute(EventAttributeHelper.CreateNonEventAttribute());
            }

            // add the parameter names
            for (int i = 0; i < parameterMapping.Count; i++)
            {
                var parameter = parameterMapping[i];
                m.DefineParameter(i + 1, ParameterAttributes.In, parameter.Name);
            }

            if (interfaceMethod.IsAbstract || !interfaceMethod.DeclaringType.IsSubclassOf(typeof(EventSource)))
            {
                // for interface methods, implement a call to write event
                ProxyHelper.EmitDefaultValue(m.GetILGenerator(), m.ReturnType);
                if (EmitIsEnabled(m, eventAttribute))
                {
                    EmitCallWriteEvent(invocationContext, m, eventAttribute, parameterMapping);
                }

                // since EventSource only accepts non-virtual methods, and we need a virtual method to implement the abstract method
                // we need to implement a wrapper method on the interface that calls into the base method
                // and handles the bundling/unbundling of parameters
                MethodBuilder im = _typeBuilder.DefineMethod("_" + methodName, MethodAttributes.Public | MethodAttributes.Virtual);
                ProxyHelper.CopyMethodSignature(interfaceMethod, im);
                ProxyHelper.EmitDefaultValue(im.GetILGenerator(), im.ReturnType);
                if (EmitIsEnabled(im, eventAttribute))
                {
                    EmitDirectProxy(invocationContext, im, m, parameterMapping);
                }

                // if this is an interface, then tell the system to map our method to the interface implementation
                if (interfaceMethod.IsAbstract)
                {
                    _typeBuilder.DefineMethodOverride(im, interfaceMethod);
                }
            }
            else
            {
                // we are implementing a non-abstract method in event source, then
                // all we can do is call the base implementation
                EmitDirectProxy(invocationContext, m, interfaceMethod, parameterMapping);
            }

            return(m);
        }
예제 #2
0
        /// <summary>
        /// Emits the implementation of a given interface method.
        /// </summary>
        /// <param name="executeMethod">The execute method to implement.</param>
        private void EmitMethodImpl(MethodInfo executeMethod, List <Tuple <FieldInfo, object> > valuesToSet)
        {
            /*
             * public TReturn Method (params)
             * {
             *		var scope = new EventActivityScope(true);
             *		try
             *		{
             *			_log.Method(params);
             *			object value = _execute.Method(params);
             *			_log.Method_Completed(value);
             *		}
             *		catch (Exception e)
             *		{
             *			_log.Method_Faulted(e);
             *			throw;
             *		}
             *		finally
             *		{
             *			scope.Dispose();
             *		}
             * }
             */

            var invocationContext = new InvocationContext(executeMethod, InvocationContextTypes.MethodCall);

            // start building the interface
            MethodBuilder m = _typeBuilder.DefineMethod(executeMethod.Name, MethodAttributes.Public | MethodAttributes.Virtual);

            ProxyHelper.CopyMethodSignature(executeMethod, m);
            var parameterTypes = executeMethod.GetParameters().Select(p => p.ParameterType).ToArray();

            ILGenerator mIL = m.GetILGenerator();

            // set up a place to hold the return value
            LocalBuilder returnValue = null;

            if (m.ReturnType != typeof(void))
            {
                returnValue = mIL.DeclareLocal(m.ReturnType);
            }

            // set up the activity scope
            LocalBuilder scope = null;

            if (_callWithActivityScope)
            {
                scope = mIL.DeclareLocal(typeof(EventActivityScope));
                mIL.Emit(OpCodes.Ldc_I4_1);
                mIL.Emit(OpCodes.Newobj, typeof(EventActivityScope).GetConstructor(new Type[] { typeof(bool) }));
                mIL.Emit(OpCodes.Stloc, scope);
            }

            // start the try block
            mIL.BeginExceptionBlock();

            // call the method on the log that matches the execute method
            var targetParameterTypes = parameterTypes.Select(p => p.IsGenericParameter ? TypeImplementer.GetTypeSupportedByEventSource(p) : p).ToArray();
            var logMethod            = DiscoverMethod(_logField.FieldType, executeMethod.Name, String.Empty, targetParameterTypes);

            if (logMethod != null)
            {
                // call the log method and throw away the result if there is one
                EmitBaseMethodCall(m, invocationContext, _logField, executeMethod, logMethod, valuesToSet);
                if (logMethod.ReturnType != typeof(void))
                {
                    mIL.Emit(OpCodes.Pop);
                }
            }

            // call execute
            EmitBaseMethodCall(m, invocationContext, _executeField, executeMethod, executeMethod, valuesToSet);
            if (executeMethod.ReturnType != typeof(void))
            {
                mIL.Emit(OpCodes.Stloc, returnValue);
            }

            // if there is a completed method, then call that
            var completedParameterTypes = (executeMethod.ReturnType == typeof(void)) ? Type.EmptyTypes : new Type[] { executeMethod.ReturnType };
            var completedMethod         = DiscoverMethod(_logField.FieldType, executeMethod.Name, TypeImplementer.CompletedSuffix, completedParameterTypes);

            if (completedMethod != null)
            {
                // load this._log
                mIL.Emit(OpCodes.Ldarg_0);
                mIL.Emit(OpCodes.Ldfld, _logField);

                // load the value from the local variable
                if (executeMethod.ReturnType != typeof(void))
                {
                    mIL.Emit(OpCodes.Ldloc, returnValue);
                }

                mIL.Emit(OpCodes.Call, completedMethod);
                if (completedMethod.ReturnType != typeof(void))
                {
                    mIL.Emit(OpCodes.Pop);
                }
            }

            // handle exceptions by logging them and rethrowing
            mIL.BeginCatchBlock(typeof(Exception));
            var faultedMethod = DiscoverMethod(_logField.FieldType, executeMethod.Name, TypeImplementer.FaultedSuffix, new Type[] { typeof(Exception) });

            if (faultedMethod != null)
            {
                // save the exception
                var exception = mIL.DeclareLocal(typeof(Exception));
                mIL.Emit(OpCodes.Stloc, exception);

                // load this._log
                mIL.Emit(OpCodes.Ldarg_0);
                mIL.Emit(OpCodes.Ldfld, _logField);

                // load the exception
                mIL.Emit(OpCodes.Ldloc, exception);

                // call the fault handler
                mIL.Emit(OpCodes.Call, faultedMethod);
                if (faultedMethod.ReturnType != typeof(void))
                {
                    mIL.Emit(OpCodes.Pop);
                }
            }

            mIL.Emit(OpCodes.Rethrow);

            // clean up the activity scope
            if (_callWithActivityScope)
            {
                mIL.BeginFinallyBlock();
                mIL.Emit(OpCodes.Ldloc, scope);
                mIL.Emit(OpCodes.Callvirt, typeof(EventActivityScope).GetMethod("Dispose"));
            }

            mIL.EndExceptionBlock();

            // return the result
            if (executeMethod.ReturnType != typeof(void))
            {
                mIL.Emit(OpCodes.Ldloc, returnValue);
            }
            mIL.Emit(OpCodes.Ret);
        }