public override IReadOnlyCollection <ParameterMapping> ProvideParameterMapping(System.Reflection.MethodInfo methodInfo)
            {
                List <ParameterMapping> mapping = new List <ParameterMapping>();

                var email = methodInfo.GetParameters()[0];

                var from = new ParameterMapping("from");

                mapping.Add(from);
                from.AddSource(email, (EmailChange e) => e.From);

                var to = new ParameterMapping("to");

                to.AddSource(email, (EmailChange e) => e.To);
                mapping.Add(to);

                var when = new ParameterMapping("when");

                when.AddSource(email, (EmailChange e) => e.When);
                mapping.Add(when);

                var domain = new ParameterMapping("domain");

                domain.AddSource(email, (EmailChange e) => e.GetDomain());
                mapping.Add(domain);

                return(mapping.AsReadOnly());
            }
            public override IReadOnlyCollection <ParameterMapping> ProvideParameterMapping(System.Reflection.MethodInfo methodInfo)
            {
                List <ParameterMapping> mapping = new List <ParameterMapping>();

                var email = methodInfo.GetParameters()[0];

                var from = new ParameterMapping("from");

                mapping.Add(from);
                from.AddSource(email, (OtherClass o) => o.AMethodNotShared());

                return(mapping.AsReadOnly());
            }
            public override IReadOnlyCollection <ParameterMapping> ProvideParameterMapping(System.Reflection.MethodInfo methodInfo)
            {
                var mappings = new List <ParameterMapping>();
                var mapping  = new ParameterMapping("data");

                mappings.Add(mapping);
                foreach (var p in methodInfo.GetParameters().Reverse())
                {
                    mapping.AddSource(p);
                }

                return(mappings.AsReadOnly());
            }
        /// <summary>
        /// Emits a method to complement an interface method. The complement method will have a suffix such as _Completed,
        /// and will take one parameter.
        /// </summary>
        /// <param name="invocationContext">The InvocationContext for this call.</param>
        /// <param name="suffix">The suffix to use on the method.</param>
        /// <param name="parameterType">The type of the parameter of the method.</param>
        /// <param name="parameterName">The name of the parameter of the method.</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 EmitMethodComplementImpl(InvocationContext invocationContext, string suffix, Type parameterType, string parameterName, MethodInfo beginMethod, ref int eventId, EventKeywords autoKeyword, MethodBuilder faultedMethod)
        {
            var interfaceMethod = invocationContext.MethodInfo;

            // if there is a NonEvent attribute, then no need to emit this method
            if (interfaceMethod.GetCustomAttribute <NonEventAttribute>() != null)
            {
                return(null);
            }

            // if the method ends in _Completed, then don't emit another one
            if (interfaceMethod.Name.EndsWith(suffix, StringComparison.OrdinalIgnoreCase))
            {
                return(null);
            }

            var methodName = beginMethod.Name + suffix;

            // if the interface already has a _Completed method with the same parameter, don't emit a new one
            var parameterTypes = parameterType == typeof(void) ? Type.EmptyTypes : new Type[] { parameterType };

            if (interfaceMethod.DeclaringType.GetMethod(methodName, parameterTypes) != null)
            {
                return(null);
            }

            // create a single parameter for the return value, and a context parameter if its supported
            var parameterMappings = new List <ParameterMapping>();

            if (parameterType != typeof(void))
            {
                var mapping = new ParameterMapping(parameterName);
                mapping.AddSource(new ParameterDefinition(parameterName, 0, parameterType));
                parameterMappings.Add(mapping);
            }

            if (SupportsContext(invocationContext))
            {
                parameterMappings.Add(new ParameterMapping(Context));
            }

            // 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 startEventAttribute = interfaceMethod.GetCustomAttribute <EventAttribute>() ?? new EventAttribute(eventId);
            EventAttribute eventAttribute      = _eventAttributeProvider.CopyEventAttribute(startEventAttribute, invocationContext, eventId);

            eventId = Math.Max(eventId, eventAttribute.EventId + 1);
            if (eventAttribute.Keywords == EventKeywords.None)
            {
                eventAttribute.Keywords = autoKeyword;
            }

            // define the internal method
            MethodBuilder m = _typeBuilder.DefineMethod(methodName, MethodAttributes.Public, typeof(void), parameterMappings.Select(p => p.CleanTargetType).ToArray());

            if (parameterMappings.Any())
            {
                m.DefineParameter(1, ParameterAttributes.None, parameterMappings[0].Name);
            }
            m.SetCustomAttribute(EventAttributeHelper.ConvertEventAttributeToAttributeBuilder(eventAttribute));

            // if we have a return type, then we need to implement two methods
            if (parameterTypes.Length == 1)
            {
                EmitCallWriteEvent(invocationContext, m, eventAttribute, parameterMappings);

                // emit an overloaded wrapper method that calls the method when it's enabled
                // note this is a non-event so EventSource doesn't try to log it
                MethodBuilder im = _typeBuilder.DefineMethod(methodName, MethodAttributes.Public);
                ProxyHelper.CopyGenericSignature(interfaceMethod, im);
                im.SetReturnType(parameterTypes[0]);
                im.SetParameters(parameterTypes);

                // mark the method as a non-event
                im.SetCustomAttribute(EventAttributeHelper.CreateNonEventAttribute());

                // put the return value on the stack so we can return the value as a passthrough
                im.GetILGenerator().Emit(OpCodes.Ldarg_1);

                if (EmitIsEnabled(im, eventAttribute))
                {
                    EmitTaskCompletion(im, parameterType, faultedMethod);
                    EmitDirectProxy(invocationContext, im, m, parameterMappings);
                }

                return(im);
            }
            else
            {
                // the method does not have a return value
                // so create the internal method that calls WriteEvent
                ProxyHelper.EmitDefaultValue(m.GetILGenerator(), m.ReturnType);
                if (EmitIsEnabled(m, eventAttribute))
                {
                    EmitCallWriteEvent(invocationContext, m, eventAttribute, parameterMappings);
                }

                return(m);
            }
        }
            public override IReadOnlyCollection<ParameterMapping> ProvideParameterMapping(System.Reflection.MethodInfo methodInfo)
            {
                List<ParameterMapping> mapping = new List<ParameterMapping>();

                var email = methodInfo.GetParameters()[0];

                var from = new ParameterMapping("from");
                mapping.Add(from);
                from.AddSource(email, (EmailChange e) => e.From);

                var to = new ParameterMapping("to");
                to.AddSource(email, (EmailChange e) => e.To);
                mapping.Add(to);

                var when = new ParameterMapping("when");
                when.AddSource(email, (EmailChange e) => e.When);
                mapping.Add(when);

                var domain = new ParameterMapping("domain");
                domain.AddSource(email, (EmailChange e) => e.GetDomain());
                mapping.Add(domain);

                return mapping.AsReadOnly();
            }
            public override IReadOnlyCollection<ParameterMapping> ProvideParameterMapping(System.Reflection.MethodInfo methodInfo)
            {
                List<ParameterMapping> mapping = new List<ParameterMapping>();

                var email = methodInfo.GetParameters()[0];

                var from = new ParameterMapping("from");
                mapping.Add(from);
                from.AddSource(email, (OtherClass o) => o.AMethodNotShared());

                return mapping.AsReadOnly();
            }
            public override IReadOnlyCollection<ParameterMapping> ProvideParameterMapping(System.Reflection.MethodInfo methodInfo)
            {
                var mappings = new List<ParameterMapping>();
                var mapping = new ParameterMapping("data");
                mappings.Add(mapping);
                foreach (var p in methodInfo.GetParameters().Reverse())
                    mapping.AddSource(p);

                return mappings.AsReadOnly();
            }
		/// <summary>
		/// Emits a method to complement an interface method. The complement method will have a suffix such as _Completed,
		/// and will take one parameter.
		/// </summary>
		/// <param name="invocationContext">The InvocationContext for this call.</param>
		/// <param name="suffix">The suffix to use on the method.</param>
		/// <param name="parameterType">The type of the parameter of the method.</param>
		/// <param name="parameterName">The name of the parameter of the method.</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 EmitMethodComplementImpl(InvocationContext invocationContext, string suffix, Type parameterType, string parameterName, MethodInfo beginMethod, ref int eventId, EventKeywords autoKeyword, MethodBuilder faultedMethod)
		{
			var interfaceMethod = invocationContext.MethodInfo;

			// if there is a NonEvent attribute, then no need to emit this method
			if (interfaceMethod.GetCustomAttribute<NonEventAttribute>() != null)
				return null;

			// if the method ends in _Completed, then don't emit another one
			if (interfaceMethod.Name.EndsWith(suffix, StringComparison.OrdinalIgnoreCase))
				return null;

			var methodName = beginMethod.Name + suffix;

			// if the interface already has a _Completed method with the same parameter, don't emit a new one
			var parameterTypes = parameterType == typeof(void) ? Type.EmptyTypes : new Type[] { parameterType };
			if (interfaceMethod.DeclaringType.GetMethod(methodName, parameterTypes) != null)
				return null;

			// create a single parameter for the return value, and a context parameter if its supported
			var parameterMappings = new List<ParameterMapping>();
			if (parameterType != typeof(void))
			{
				var mapping = new ParameterMapping(parameterName);
				mapping.AddSource(new ParameterDefinition(parameterName, 0, parameterType));
				parameterMappings.Add(mapping);
			}

			if (SupportsContext(invocationContext))
				parameterMappings.Add(new ParameterMapping(Context));

			// 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 startEventAttribute = interfaceMethod.GetCustomAttribute<EventAttribute>() ?? new EventAttribute(eventId);
			EventAttribute eventAttribute = _eventAttributeProvider.CopyEventAttribute(startEventAttribute, invocationContext, eventId);
			eventId = Math.Max(eventId, eventAttribute.EventId + 1);
			if (eventAttribute.Keywords == EventKeywords.None)
				eventAttribute.Keywords = autoKeyword;

			// define the internal method
			MethodBuilder m = _typeBuilder.DefineMethod(methodName, MethodAttributes.Public, typeof(void), parameterMappings.Select(p => p.CleanTargetType).ToArray());
			if (parameterMappings.Any())
				m.DefineParameter(1, ParameterAttributes.None, parameterMappings[0].Name);
			m.SetCustomAttribute(EventAttributeHelper.ConvertEventAttributeToAttributeBuilder(eventAttribute));

			// if we have a return type, then we need to implement two methods
			if (parameterTypes.Length == 1)
			{
				EmitCallWriteEvent(invocationContext, m, eventAttribute, parameterMappings);

				// emit an overloaded wrapper method that calls the method when it's enabled
				// note this is a non-event so EventSource doesn't try to log it
				MethodBuilder im = _typeBuilder.DefineMethod(methodName, MethodAttributes.Public);
				ProxyHelper.CopyGenericSignature(interfaceMethod, im);
				im.SetReturnType(parameterTypes[0]);
				im.SetParameters(parameterTypes);

				// mark the method as a non-event
				im.SetCustomAttribute(EventAttributeHelper.CreateNonEventAttribute());

				// put the return value on the stack so we can return the value as a passthrough
				im.GetILGenerator().Emit(OpCodes.Ldarg_1);

				if (EmitIsEnabled(im, eventAttribute))
				{
					EmitTaskCompletion(im, parameterType, faultedMethod);
					EmitDirectProxy(invocationContext, im, m, parameterMappings);
				}

				return im;
			}
			else
			{
				// the method does not have a return value
				// so create the internal method that calls WriteEvent
				ProxyHelper.EmitDefaultValue(m.GetILGenerator(), m.ReturnType);
				if (EmitIsEnabled(m, eventAttribute))
					EmitCallWriteEvent(invocationContext, m, eventAttribute, parameterMappings);

				return m;
			}
		}