/// <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);
        }