/// <summary>
 /// Emits a _Faulted version of a given event that logs the result of an operation.
 /// The _Completed event is used by TracingProxy to signal an exception in a method call.
 /// </summary>
 /// <param name="invocationContext">The InvocationContext for this call.</param>
 /// <param name="beginMethod">The begin method for this interface call.</param>
 /// <param name="eventId">The next available event ID.</param>
 /// <param name="autoKeyword">The auto-keyword to use if enabled.</param>
 /// <returns>The MethodBuilder for the method.</returns>
 private MethodBuilder EmitMethodFaultedImpl(InvocationContext invocationContext, MethodInfo beginMethod, ref int eventId, EventKeywords autoKeyword)
 {
     return EmitMethodComplementImpl(invocationContext.SpecifyType(InvocationContextTypes.MethodFaulted), FaultedSuffix, typeof(Exception), beginMethod, ref eventId, autoKeyword, null);
 }
        /// <summary>
        /// Emits the code needed to properly push an object on the stack,
        /// serializing the value if necessary.
        /// </summary>
        /// <param name="typeBuilder">The TypeBuilder for the method being built.</param>
        /// <param name="methodBuilder">The method currently being built.</param>
        /// <param name="invocationContext">The invocation context for this call.</param>
        /// <param name="invocationContexts">A list of invocation contexts that will be appended to.</param>
        /// <param name="invocationContextsField">The static field containing the array of invocation contexts at runtime.</param>
        /// <param name="parameterMapping">The mapping of source parameters to destination parameters.</param>
        /// <param name="serializationProvider">The serialization provider for the current interface.</param>
        /// <param name="serializationProviderField">
        /// The field on the current object that contains the serialization provider at runtime.
        /// This method assume the current object is stored in arg.0.
        /// </param>
        internal static void EmitSerializeValue(
			TypeBuilder typeBuilder,
			MethodBuilder methodBuilder,
			InvocationContext invocationContext,
			List<InvocationContext> invocationContexts,
			FieldBuilder invocationContextsField,
			ParameterMapping parameterMapping,
			TraceSerializationProvider serializationProvider,
			FieldBuilder serializationProviderField)
        {
            var sourceCount = parameterMapping.Sources.Count();
            if (sourceCount == 0)
                return;

            if (sourceCount == 1)
            {
                var parameter = parameterMapping.Sources.First();

                EmitSerializeValue(
                    typeBuilder,
                    methodBuilder,
                    invocationContext,
                    invocationContexts,
                    invocationContextsField,
                    parameter.Position,
                    parameter.SourceType,
                    parameterMapping.CleanTargetType,
                    parameter.Converter,
                    serializationProvider,
                    serializationProviderField);
                return;
            }

            var il = methodBuilder.GetILGenerator();

            // use the serializer to serialize the objects
            var context = new TraceSerializationContext(invocationContext.SpecifyType(InvocationContextTypes.BundleParameters), -1);
            context.EventLevel = serializationProvider.GetEventLevelForContext(context);

            if (context.EventLevel != null)
            {
                // get the object serializer from the this pointer
                il.Emit(OpCodes.Ldsfld, serializationProviderField);

                // create a new dictionary strings and values
                il.Emit(OpCodes.Newobj, typeof(Dictionary<string, string>).GetConstructor(Type.EmptyTypes));

                foreach (var parameter in parameterMapping.Sources)
                {
                    il.Emit(OpCodes.Dup);
                    il.Emit(OpCodes.Ldstr, parameter.Alias);

                    EmitSerializeValue(
                        typeBuilder,
                        methodBuilder,
                        invocationContext,
                        invocationContexts,
                        invocationContextsField,
                        parameter.Position,
                        parameter.SourceType,
                        parameterMapping.CleanTargetType,
                        parameter.Converter,
                        serializationProvider,
                        serializationProviderField);

                    var method = typeof(Dictionary<string, string>).GetMethod("Add");
                    il.Emit(OpCodes.Call, method);
                }

                // get the invocation context from the array on the provider
                il.Emit(OpCodes.Ldsfld, invocationContextsField);
                il.Emit(OpCodes.Ldc_I4, invocationContexts.Count);
                il.Emit(OpCodes.Ldelem, typeof(TraceSerializationContext));
                invocationContexts.Add(context);

                il.Emit(OpCodes.Callvirt, typeof(TraceSerializationProvider).GetMethod("ProvideSerialization", BindingFlags.Instance | BindingFlags.Public));
            }
            else
                il.Emit(OpCodes.Ldnull);
        }
 /// <summary>
 /// Emits a _Completed version of a given event that logs the result of an operation.
 /// The _Completed event is used by TracingProxy to signal the end of a method call.
 /// </summary>
 /// <param name="invocationContext">The InvocationContext for this call.</param>
 /// <param name="beginMethod">The begin method for this interface call.</param>
 /// <param name="eventId">The next available event ID.</param>
 /// <param name="autoKeyword">The auto-keyword to use if enabled.</param>
 /// <param name="faultedMethod">A faulted method to call or null if no other faulted method is available.</param>
 /// <returns>The MethodBuilder for the method.</returns>
 private MethodBuilder EmitMethodCompletedImpl(InvocationContext invocationContext, MethodInfo beginMethod, ref int eventId, EventKeywords autoKeyword, MethodBuilder faultedMethod)
 {
     return EmitMethodComplementImpl(invocationContext.SpecifyType(InvocationContextTypes.MethodCompletion), CompletedSuffix, invocationContext.MethodInfo.ReturnType, beginMethod, ref eventId, autoKeyword, faultedMethod);
 }