public static Delegate CreateOnShouldListenToDelegate(Type activitySourceType, MethodInfo onShouldListenToMethodInfo)
        {
            var dynMethod = new DynamicMethod(
                "OnShouldListenToDyn",
                typeof(bool),
                new[] { activitySourceType },
                typeof(ActivityListener).Module,
                true);

            var proxyResult = DuckType.GetOrCreateProxyType(typeof(IActivitySource), activitySourceType);
            var proxyType   = proxyResult.ProxyType;

            if (proxyType is null)
            {
                ThrowHelper.ThrowNullReferenceException($"Resulting proxy type after ducktyping {activitySourceType} is null");
            }

            var method        = onShouldListenToMethodInfo.MakeGenericMethod(proxyType);
            var proxyTypeCtor = proxyType.GetConstructors()[0];

            var il = dynMethod.GetILGenerator();

            il.Emit(OpCodes.Ldarg_0);
            il.Emit(OpCodes.Newobj, proxyTypeCtor);
            il.EmitCall(OpCodes.Call, method, null);
            il.Emit(OpCodes.Ret);

            return(dynMethod.CreateDelegate(typeof(Func <,>).MakeGenericType(activitySourceType, typeof(bool))));
        }
Beispiel #2
0
    static void Main(string[] args)
    {
        dynamic person = new { Name = "Peter" };
        var     p      = DuckType.As <IPerson>(person);

        Console.WriteLine(p.Name);
    }
Beispiel #3
0
    public int SubtractFromNumToSpawn(int num, DuckType unit)
    {
        num--;
        if (num <= 0)
        {
            if (unit == type[0])
            {
                typeTemp.RemoveAt(0);
            }

            if (unit == type[1])
            {
                typeTemp.RemoveAt(1);
            }

            if (unit == type[2])
            {
                typeTemp.RemoveAt(2);
            }
        }

        if (typeTemp.Count == 0)
        {
            CancelInvoke("SpawnObject");
        }

        return(num);
    }
Beispiel #4
0
        public static MappedDiagnosticsContextSetterProxy GetMdcProxy(Assembly nlogAssembly)
        {
            var mdcType = nlogAssembly.GetType("NLog.MappedDiagnosticsContext");

            if (mdcType is not null)
            {
                // NLog 2.0+
                var createTypeResult = DuckType.GetOrCreateProxyType(typeof(MappedDiagnosticsContextSetterProxy), mdcType);
                if (createTypeResult.Success)
                {
                    return(createTypeResult.CreateInstance <MappedDiagnosticsContextSetterProxy>(instance: null));
                }
            }

            mdcType = nlogAssembly.GetType("NLog.MDC");
            if (mdcType is not null)
            {
                // NLog 1.0+
                var createTypeResult = DuckType.GetOrCreateProxyType(typeof(MappedDiagnosticsContextSetterProxy), mdcType);
                if (createTypeResult.Success)
                {
                    return(createTypeResult.CreateInstance <MappedDiagnosticsContextSetterProxy>(instance: null));
                }
            }

            return(null);
        }
        public void Initialize()
        {
            Baz baz = new Baz();

            foo = DuckType.Cast <Foo>(baz);
            Assert.AreNotSame(baz, foo);
        }
 [Ignore] //Manual test
 public void As_Loop()
 {
     foreach (object obj in GetObjects())
     {
         Assert.IsNotNull(DuckType.As <IHasValue>(obj).Value);
     }
 }
Beispiel #7
0
        public void CastToImplementedType()
        {
            Baz baz = new Baz();
            Foo foo = DuckType.Cast <Foo>(baz);

            Assert.AreSame(baz, foo);
            foo.Bar();
        }
Beispiel #8
0
 public IQuackable getDuck(DuckType duckType)
 {
     if (DuckDictionary.ContainsKey(duckType))
     {
         return DuckDictionary[duckType];
     }
     else return null;
 }
Beispiel #9
0
        public void EmptyMethodNoReturnType()
        {
            Baz baz = new Baz();
            Foo foo = DuckType.Cast <Foo>(baz);

            Assert.AreNotSame(baz, foo);
            foo.Bar();
        }
        public void As_Invalid()
        {
            string        expected = Guid.NewGuid().ToString();
            BespokeString bespoke  = new BespokeString(expected);

            Assert.IsNotInstanceOfType(bespoke, typeof(IHasValue));
            IHasValue duck = DuckType.As <IHasValue>(bespoke);

            Assert.IsNull(duck);
        }
        public void OverloadTestSameReturnTypes()
        {
            Baz  baz = new Baz();
            Quux foo = DuckType.Cast <Quux>(baz);

            Assert.AreNotSame(baz, foo);

            Assert.AreEqual("Hello World!", foo.Qux("Hello World!"));
            Assert.AreEqual("2", foo.Qux(2));
        }
    public void ChangeType(DuckType duckType)
    {
        type = duckType;

        GetComponent <Attack>().type = type;
        GetComponent <Health>().type = type;
        GetComponent <Move>().type   = type;

        GetComponent <SpriteRenderer>().sprite = type.sprite;
    }
        public void As_Struct()
        {
            int        expected = _random.Next();
            BespokeInt bespoke  = new BespokeInt(expected);

            Assert.IsNotInstanceOfType(bespoke, typeof(IHasValue));
            IHasValue duck = DuckType.As <IHasValue>(bespoke);

            Assert.IsInstanceOfType(duck, typeof(IHasValue));
            Assert.AreEqual(expected, duck.Value);
        }
        public void As()
        {
            DateTime        expected = new DateTime(_random.Next(1900, 2000), _random.Next(1, 12), _random.Next(1, 28));
            BespokeDateTime bespoke  = new BespokeDateTime(expected);

            Assert.IsNotInstanceOfType(bespoke, typeof(IHasValue));
            IHasValue duck = DuckType.As <IHasValue>(bespoke);

            Assert.IsInstanceOfType(duck, typeof(IHasValue));
            Assert.AreEqual(expected, duck.Value);
        }
Beispiel #15
0
 public ExprDotMethodForgeNoDuck(
     string optionalStatementName,
     MethodInfo method,
     ExprForge[] parameters,
     DuckType type)
 {
     OptionalStatementName = optionalStatementName;
     Method = method;
     Parameters = parameters;
     this.type = type;
 }
        public void TestMethodParameters()
        {
            Baz baz = new Baz();
            Foo foo = DuckType.Cast <Foo>(baz);

            Assert.AreNotSame(baz, foo);
            foo.MethodString("test");
            foo.MethodInt(1337);
            foo.MethodBool(true);
            foo.MethodLong(1);
        }
        public void OverloadTestDifferentReturnTypes()
        {
            Baz baz = new Baz();
            Foo foo = DuckType.Cast <Foo>(baz);

            Assert.AreNotSame(baz, foo);

            Assert.AreEqual("Hello World!", foo.Bar("Hello"));
            Assert.AreEqual(4, foo.Bar(2));
            Assert.AreEqual(false, foo.Bar(true));
        }
Beispiel #18
0
        static DiagnosticObserverListener()
        {
            try
            {
                var diagnosticListenerType = Type.GetType("System.Diagnostics.DiagnosticListener, System.Diagnostics.DiagnosticSource");
                if (diagnosticListenerType is null)
                {
                    ThrowHelper.ThrowNullReferenceException("System.Diagnostics.DiagnosticListener cannot be found.");
                }

                var sourceProxyResult          = DuckType.GetOrCreateProxyType(typeof(ISource), diagnosticListenerType);
                var sourceProxyResultProxyType = sourceProxyResult.ProxyType;
                if (sourceProxyResultProxyType is null)
                {
                    ThrowHelper.ThrowNullReferenceException($"Resulting proxy type after ducktyping {diagnosticListenerType} is null");
                }

                var onShouldListenToMethodInfo = typeof(ActivityListenerHandler).GetMethod(nameof(ActivityListenerHandler.OnShouldListenTo), BindingFlags.Static | BindingFlags.Public);
                if (onShouldListenToMethodInfo is null)
                {
                    ThrowHelper.ThrowNullReferenceException("ActivityListenerHandler.OnShouldListenTo cannot be found.");
                }

                var onShouldListenToMethod = onShouldListenToMethodInfo.MakeGenericMethod(sourceProxyResultProxyType);

                var onShouldListenToResultMethodInfo = typeof(DiagnosticObserverListener).GetMethod(nameof(DiagnosticObserverListener.OnShouldListenToResult), BindingFlags.Static | BindingFlags.Public);
                if (onShouldListenToResultMethodInfo is null)
                {
                    ThrowHelper.ThrowNullReferenceException("DiagnosticObserverListener.OnShouldListenToResult cannot be found.");
                }

                var onShouldListenToResultMethod = onShouldListenToResultMethodInfo.MakeGenericMethod(sourceProxyResultProxyType);

                // Create delegate for OnShouldListenTo<T> where T is Source
                var onShouldListenToDyn = new DynamicMethod("OnShouldListenToDyn", typeof(void), new[] { typeof(object) }, typeof(ActivityListener).Module, true);

                var sourceProxyResultProxyTypeCtor = sourceProxyResultProxyType.GetConstructors()[0];
                var onShouldListenToDynIl          = onShouldListenToDyn.GetILGenerator();
                onShouldListenToDynIl.Emit(OpCodes.Ldarg_0);
                onShouldListenToDynIl.Emit(OpCodes.Newobj, sourceProxyResultProxyTypeCtor);
                onShouldListenToDynIl.Emit(OpCodes.Dup);
                onShouldListenToDynIl.EmitCall(OpCodes.Call, onShouldListenToMethod, null);
                onShouldListenToDynIl.EmitCall(OpCodes.Call, onShouldListenToResultMethod, null);
                onShouldListenToDynIl.Emit(OpCodes.Ret);
                OnShouldListenToDelegate = (Action <object>)onShouldListenToDyn.CreateDelegate(typeof(Action <object>));
            }
            catch (Exception ex)
            {
                Log.Error(ex, "Error on DiagnosticObserverListener static constructor");
                OnShouldListenToDelegate = o => { };
            }
        }
Beispiel #19
0
    public static bool DuckIs <T>(this object instance)
    {
        if (instance is null)
        {
            DuckTypeTargetObjectInstanceIsNull.Throw();
        }

        if (DuckType.CreateCache <T> .IsVisible)
        {
            return(DuckType.CanCreate <T>(instance));
        }

        return(false);
    }
Beispiel #20
0
    public static bool DuckIs(this object instance, Type targetType)
    {
        if (instance is null)
        {
            DuckTypeTargetObjectInstanceIsNull.Throw();
        }

        if (targetType != null && (targetType.IsPublic || targetType.IsNestedPublic))
        {
            return(DuckType.CanCreate(targetType, instance));
        }

        return(false);
    }
Beispiel #21
0
        public static Duck GetDuck(DuckType muscovy)
        {
            switch (muscovy)
            {
            case DuckType.Muscovy:
                return(new MuscovyDuck());

            case DuckType.Plastic:
                return(new PlasticDuck());

            default:
                return(null);
            }
        }
Beispiel #22
0
    public static object DuckAs(this object instance, Type targetType)
    {
        if (instance is null)
        {
            DuckTypeTargetObjectInstanceIsNull.Throw();
        }

        if (targetType != null && (targetType.IsPublic || targetType.IsNestedPublic))
        {
            DuckType.CreateTypeResult proxyResult = DuckType.GetOrCreateProxyType(targetType, instance.GetType());
            if (proxyResult.Success)
            {
                return(proxyResult.CreateInstance(instance));
            }
        }

        return(null);
    }
Beispiel #23
0
        private static T ConvertType <T>(object value)
        {
            var conversionType = typeof(T);

            if (value is null || conversionType == typeof(object))
            {
                return((T)value);
            }

            Type valueType = value.GetType();

            if (valueType == conversionType || conversionType.IsAssignableFrom(valueType))
            {
                return((T)value);
            }

            // Finally we try to duck type
            return(DuckType.Create <T>(value));
        }
Beispiel #24
0
    public static bool TryDuckCast(this object instance, Type targetType, out object value)
    {
        if (instance is null)
        {
            DuckTypeTargetObjectInstanceIsNull.Throw();
        }

        if (targetType != null && (targetType.IsPublic || targetType.IsNestedPublic))
        {
            DuckType.CreateTypeResult proxyResult = DuckType.GetOrCreateProxyType(targetType, instance.GetType());
            if (proxyResult.Success)
            {
                value = proxyResult.CreateInstance(instance);
                return(true);
            }
        }

        value = default;
        return(false);
    }
Beispiel #25
0
        public static Duck GetDuckByType(DuckType duckType)
        {
            switch (duckType)
            {
            case DuckType.RUBBER_DUCK:
                return(new Duck(
                           new NoFlyer(),
                           new MutedQuacker()
                           ));

            case DuckType.FLYING_BUT_LOUD_DUCK:
                return(new Duck(
                           new GoodFlyer(),
                           new LoudQuacker()
                           ));

            default:
                throw new Exception("There is no duck defined with the type: " + duckType.ToString());
            }
        }
Beispiel #26
0
        static DiagnosticSourceEventListener()
        {
            try
            {
                var activityType             = Type.GetType("System.Diagnostics.Activity, System.Diagnostics.DiagnosticSource", throwOnError: true);
                var onNextActivityMethodInfo = typeof(DiagnosticSourceEventListener).GetMethod(nameof(DiagnosticSourceEventListener.OnNextActivity), BindingFlags.Static | BindingFlags.NonPublic);
                if (onNextActivityMethodInfo is null)
                {
                    ThrowHelper.ThrowNullReferenceException("DiagnosticSourceEventListener.OnNextActivity cannot be found.");
                }

                // Create delegate for OnNext + Activity
                var onNextActivityDynMethod = new DynamicMethod("OnNextActivityDyn", typeof(void), new[] { typeof(string), typeof(KeyValuePair <string, object>), typeof(object) }, typeof(ActivityListener).Module, true);

                DuckType.CreateTypeResult onNextActivityProxyResult;
                if (activityType !.GetField("_traceId", DuckAttribute.DefaultFlags) is not null)
                {
                    onNextActivityProxyResult = DuckType.GetOrCreateProxyType(typeof(IW3CActivity), activityType);
                }
                else
                {
                    onNextActivityProxyResult = DuckType.GetOrCreateProxyType(typeof(IActivity), activityType);
                }

                var onNextActivityProxyResultProxyType = onNextActivityProxyResult.ProxyType;
                if (onNextActivityProxyResultProxyType is null)
                {
                    ThrowHelper.ThrowNullReferenceException($"Resulting proxy type after ducktyping {activityType} is null");
                }

                var onNextActivityMethod        = onNextActivityMethodInfo.MakeGenericMethod(onNextActivityProxyResultProxyType);
                var onNextActivityProxyTypeCtor = onNextActivityProxyResultProxyType.GetConstructors()[0];
                var onNextActivityDynMethodIl   = onNextActivityDynMethod.GetILGenerator();
                onNextActivityDynMethodIl.Emit(OpCodes.Ldarg_0);
                onNextActivityDynMethodIl.Emit(OpCodes.Ldarg_1);
                onNextActivityDynMethodIl.Emit(OpCodes.Ldarg_2);
                onNextActivityDynMethodIl.Emit(OpCodes.Newobj, onNextActivityProxyTypeCtor);
                onNextActivityDynMethodIl.EmitCall(OpCodes.Call, onNextActivityMethod, null);
                onNextActivityDynMethodIl.Emit(OpCodes.Ret);
                OnNextActivityDelegate = (Action <string, KeyValuePair <string, object>, object?>)onNextActivityDynMethod.CreateDelegate(typeof(Action <string, KeyValuePair <string, object>, object?>));
            }
Beispiel #27
0
        private void CheckDuckType()
        {
            if (rdbMallard.Checked)
            {
                _ducktype = DuckType.MallardDuck;
            }
            if (rdbRedHead.Checked)
            {
                _ducktype = DuckType.RedHeadDuck;
            }
            if (rdbRubber.Checked)
            {
                _ducktype = DuckType.RubberDuck;
            }
            if (rdbDecoyDuck.Checked)
            {
                _ducktype = DuckType.DecoyDuck;
            }

            switch (_ducktype)
            {
            case DuckType.MallardDuck:
                _duck = new MallardDuck();
                break;

            case DuckType.RedHeadDuck:
                _duck = new RedHeadDuck();
                break;

            case DuckType.RubberDuck:
                _duck = new RubberDuck();
                break;

            case DuckType.DecoyDuck:
                _duck = new DecoyDuck();
                break;
            }
        }
        public static Delegate CreateOnActivityStoppedDelegate(Type activityType, MethodInfo onActivityStoppedMethodInfo)
        {
            var dynMethod = new DynamicMethod(
                "OnActivityStoppedDyn",
                typeof(void),
                new[] { activityType },
                typeof(ActivityListener).Module,
                true);

            var activityProxyType = typeof(IActivity5);

            if (activityType.Assembly.GetName().Version?.Major >= 6)
            {
                activityProxyType = typeof(IActivity6);
            }

            var proxyResult = DuckType.GetOrCreateProxyType(activityProxyType, activityType);
            var proxyType   = proxyResult.ProxyType;

            if (proxyType is null)
            {
                ThrowHelper.ThrowNullReferenceException($"Resulting proxy type after ducktyping {activityType} is null");
            }

            var method        = onActivityStoppedMethodInfo.MakeGenericMethod(proxyType);
            var proxyTypeCtor = proxyType.GetConstructors()[0];

            var il = dynMethod.GetILGenerator();

            il.Emit(OpCodes.Ldarg_0);
            il.Emit(OpCodes.Newobj, proxyTypeCtor);
            il.EmitCall(OpCodes.Call, method, null);
            il.Emit(OpCodes.Ret);

            return(dynMethod.CreateDelegate(typeof(Action <>).MakeGenericType(activityType)));
        }
 public bool IsA(DuckType type)
 {
     return Types[type].All(Properties.ContainsKey) && Inheritance[type].All(IsA);
 }
        internal static DynamicMethod CreateEndMethodDelegate(Type integrationType, Type targetType, Type returnType)
        {
            /*
             * OnMethodEnd signatures with 3 or 4 parameters with 1 or 2 generics:
             *      - CallTargetReturn<TReturn> OnMethodEnd<TTarget, TReturn>(TTarget instance, TReturn returnValue, Exception exception, CallTargetState state);
             *      - CallTargetReturn<TReturn> OnMethodEnd<TTarget, TReturn>(TReturn returnValue, Exception exception, CallTargetState state);
             *      - CallTargetReturn<[Type]> OnMethodEnd<TTarget>([Type] returnValue, Exception exception, CallTargetState state);
             *
             */

            Logger.Debug($"Creating EndMethod Dynamic Method for '{integrationType.FullName}' integration. [Target={targetType.FullName}, ReturnType={returnType.FullName}]");
            var onMethodEndMethodInfo = integrationType.GetMethod(EndMethodName, BindingFlags.Public | BindingFlags.NonPublic | BindingFlags.Static);

            if (onMethodEndMethodInfo is null)
            {
                Logger.Debug($"'{EndMethodName}' method was not found in integration type: '{integrationType.FullName}'.");
                return(null);
            }

            if (onMethodEndMethodInfo.ReturnType.GetGenericTypeDefinition() != typeof(CallTargetReturn <>))
            {
                throw new ArgumentException($"The return type of the method: {EndMethodName} in type: {integrationType.FullName} is not {nameof(CallTargetReturn)}");
            }

            var genericArgumentsTypes = onMethodEndMethodInfo.GetGenericArguments();

            if (genericArgumentsTypes.Length < 1 || genericArgumentsTypes.Length > 2)
            {
                throw new ArgumentException($"The method: {EndMethodName} in type: {integrationType.FullName} must have the generic type for the instance type.");
            }

            var onMethodEndParameters = onMethodEndMethodInfo.GetParameters();

            if (onMethodEndParameters.Length < 3)
            {
                throw new ArgumentException($"The method: {EndMethodName} with {onMethodEndParameters.Length} parameters in type: {integrationType.FullName} has less parameters than required.");
            }
            else if (onMethodEndParameters.Length > 4)
            {
                throw new ArgumentException($"The method: {EndMethodName} with {onMethodEndParameters.Length} parameters in type: {integrationType.FullName} has more parameters than required.");
            }

            if (onMethodEndParameters[onMethodEndParameters.Length - 2].ParameterType != typeof(Exception))
            {
                throw new ArgumentException($"The Exception type parameter of the method: {EndMethodName} in type: {integrationType.FullName} is missing.");
            }

            if (onMethodEndParameters[onMethodEndParameters.Length - 1].ParameterType != typeof(CallTargetState))
            {
                throw new ArgumentException($"The CallTargetState type parameter of the method: {EndMethodName} in type: {integrationType.FullName} is missing.");
            }

            var callGenericTypes = new List <Type>();

            var  mustLoadInstance          = onMethodEndParameters.Length == 4;
            var  instanceGenericType       = genericArgumentsTypes[0];
            var  instanceGenericConstraint = instanceGenericType.GetGenericParameterConstraints().FirstOrDefault();
            Type instanceProxyType         = null;

            if (instanceGenericConstraint != null)
            {
                var result = DuckType.GetOrCreateProxyType(instanceGenericConstraint, targetType);
                instanceProxyType = result.ProxyType;
                callGenericTypes.Add(instanceProxyType);
            }
            else
            {
                callGenericTypes.Add(targetType);
            }

            var  returnParameterIndex         = onMethodEndParameters.Length == 4 ? 1 : 0;
            var  isAGenericReturnValue        = onMethodEndParameters[returnParameterIndex].ParameterType.IsGenericParameter;
            Type returnValueGenericType       = null;
            Type returnValueGenericConstraint = null;
            Type returnValueProxyType         = null;

            if (isAGenericReturnValue)
            {
                returnValueGenericType       = genericArgumentsTypes[1];
                returnValueGenericConstraint = returnValueGenericType.GetGenericParameterConstraints().FirstOrDefault();
                if (returnValueGenericConstraint != null)
                {
                    var result = DuckType.GetOrCreateProxyType(returnValueGenericConstraint, returnType);
                    returnValueProxyType = result.ProxyType;
                    callGenericTypes.Add(returnValueProxyType);
                }
                else
                {
                    callGenericTypes.Add(returnType);
                }
            }
            else if (onMethodEndParameters[returnParameterIndex].ParameterType != returnType)
            {
                throw new ArgumentException($"The ReturnValue type parameter of the method: {EndMethodName} in type: {integrationType.FullName} is invalid. [{onMethodEndParameters[returnParameterIndex].ParameterType} != {returnType}]");
            }

            var callMethod = new DynamicMethod(
                $"{onMethodEndMethodInfo.DeclaringType.Name}.{onMethodEndMethodInfo.Name}.{targetType.Name}.{returnType.Name}",
                typeof(CallTargetReturn <>).MakeGenericType(returnType),
                new Type[] { targetType, returnType, typeof(Exception), typeof(CallTargetState) },
                onMethodEndMethodInfo.Module,
                true);

            var ilWriter = callMethod.GetILGenerator();

            // Load the instance if is needed
            if (mustLoadInstance)
            {
                ilWriter.Emit(OpCodes.Ldarg_0);

                if (instanceGenericConstraint != null)
                {
                    WriteCreateNewProxyInstance(ilWriter, instanceProxyType, targetType);
                }
            }

            // Load the return value
            ilWriter.Emit(OpCodes.Ldarg_1);
            if (returnValueProxyType != null)
            {
                WriteCreateNewProxyInstance(ilWriter, returnValueProxyType, returnType);
            }

            // Load the exception
            ilWriter.Emit(OpCodes.Ldarg_2);

            // Load the state
            ilWriter.Emit(OpCodes.Ldarg_3);

            // Call Method
            onMethodEndMethodInfo = onMethodEndMethodInfo.MakeGenericMethod(callGenericTypes.ToArray());
            ilWriter.EmitCall(OpCodes.Call, onMethodEndMethodInfo, null);

            // Unwrap return value proxy
            if (returnValueProxyType != null)
            {
                var unwrapReturnValue = UnwrapReturnValueMethodInfo.MakeGenericMethod(returnValueProxyType, returnType);
                ilWriter.EmitCall(OpCodes.Call, unwrapReturnValue, null);
            }

            ilWriter.Emit(OpCodes.Ret);

            Logger.Debug($"Created EndMethod Dynamic Method for '{integrationType.FullName}' integration. [Target={targetType.FullName}, ReturnType={returnType.FullName}]");
            return(callMethod);
        }
        internal static DynamicMethod CreateEndMethodDelegate(Type integrationType, Type targetType)
        {
            /*
             * OnMethodEnd signatures with 2 or 3 parameters with 1 generics:
             *      - CallTargetReturn OnMethodEnd<TTarget>(TTarget instance, Exception exception, CallTargetState state);
             *      - CallTargetReturn OnMethodEnd<TTarget>(Exception exception, CallTargetState state);
             *
             */

            Logger.Debug($"Creating EndMethod Dynamic Method for '{integrationType.FullName}' integration. [Target={targetType.FullName}]");
            var onMethodEndMethodInfo = integrationType.GetMethod(EndMethodName, BindingFlags.Public | BindingFlags.NonPublic | BindingFlags.Static);

            if (onMethodEndMethodInfo is null)
            {
                Logger.Debug($"'{EndMethodName}' method was not found in integration type: '{integrationType.FullName}'.");
                return(null);
            }

            if (onMethodEndMethodInfo.ReturnType != typeof(CallTargetReturn))
            {
                throw new ArgumentException($"The return type of the method: {EndMethodName} in type: {integrationType.FullName} is not {nameof(CallTargetReturn)}");
            }

            var genericArgumentsTypes = onMethodEndMethodInfo.GetGenericArguments();

            if (genericArgumentsTypes.Length != 1)
            {
                throw new ArgumentException($"The method: {EndMethodName} in type: {integrationType.FullName} must have a single generic type for the instance type.");
            }

            var onMethodEndParameters = onMethodEndMethodInfo.GetParameters();

            if (onMethodEndParameters.Length < 2)
            {
                throw new ArgumentException($"The method: {EndMethodName} with {onMethodEndParameters.Length} parameters in type: {integrationType.FullName} has less parameters than required.");
            }
            else if (onMethodEndParameters.Length > 3)
            {
                throw new ArgumentException($"The method: {EndMethodName} with {onMethodEndParameters.Length} parameters in type: {integrationType.FullName} has more parameters than required.");
            }

            if (onMethodEndParameters[onMethodEndParameters.Length - 2].ParameterType != typeof(Exception))
            {
                throw new ArgumentException($"The Exception type parameter of the method: {EndMethodName} in type: {integrationType.FullName} is missing.");
            }

            if (onMethodEndParameters[onMethodEndParameters.Length - 1].ParameterType != typeof(CallTargetState))
            {
                throw new ArgumentException($"The CallTargetState type parameter of the method: {EndMethodName} in type: {integrationType.FullName} is missing.");
            }

            var callGenericTypes = new List <Type>();

            var  mustLoadInstance          = onMethodEndParameters.Length == 3;
            var  instanceGenericType       = genericArgumentsTypes[0];
            var  instanceGenericConstraint = instanceGenericType.GetGenericParameterConstraints().FirstOrDefault();
            Type instanceProxyType         = null;

            if (instanceGenericConstraint != null)
            {
                var result = DuckType.GetOrCreateProxyType(instanceGenericConstraint, targetType);
                instanceProxyType = result.ProxyType;
                callGenericTypes.Add(instanceProxyType);
            }
            else
            {
                callGenericTypes.Add(targetType);
            }

            var callMethod = new DynamicMethod(
                $"{onMethodEndMethodInfo.DeclaringType.Name}.{onMethodEndMethodInfo.Name}",
                typeof(CallTargetReturn),
                new Type[] { targetType, typeof(Exception), typeof(CallTargetState) },
                onMethodEndMethodInfo.Module,
                true);

            var ilWriter = callMethod.GetILGenerator();

            // Load the instance if is needed
            if (mustLoadInstance)
            {
                ilWriter.Emit(OpCodes.Ldarg_0);

                if (instanceGenericConstraint != null)
                {
                    WriteCreateNewProxyInstance(ilWriter, instanceProxyType, targetType);
                }
            }

            // Load the exception
            ilWriter.Emit(OpCodes.Ldarg_1);

            // Load the state
            ilWriter.Emit(OpCodes.Ldarg_2);

            // Call Method
            onMethodEndMethodInfo = onMethodEndMethodInfo.MakeGenericMethod(callGenericTypes.ToArray());
            ilWriter.EmitCall(OpCodes.Call, onMethodEndMethodInfo, null);

            ilWriter.Emit(OpCodes.Ret);

            Logger.Debug($"Created EndMethod Dynamic Method for '{integrationType.FullName}' integration. [Target={targetType.FullName}]");
            return(callMethod);
        }
        internal static DynamicMethod CreateBeginMethodDelegate(Type integrationType, Type targetType, Type[] argumentsTypes)
        {
            /*
             * OnMethodBegin signatures with 1 or more parameters with 1 or more generics:
             *      - CallTargetState OnMethodBegin<TTarget>(TTarget instance);
             *      - CallTargetState OnMethodBegin<TTarget, TArg1>(TTarget instance, TArg1 arg1);
             *      - CallTargetState OnMethodBegin<TTarget, TArg1, TArg2>(TTarget instance, TArg1 arg1, TArg2);
             *      - CallTargetState OnMethodBegin<TTarget, TArg1, TArg2, ...>(TTarget instance, TArg1 arg1, TArg2, ...);
             *      - CallTargetState OnMethodBegin<TTarget>();
             *      - CallTargetState OnMethodBegin<TTarget, TArg1>(TArg1 arg1);
             *      - CallTargetState OnMethodBegin<TTarget, TArg1, TArg2>(TArg1 arg1, TArg2);
             *      - CallTargetState OnMethodBegin<TTarget, TArg1, TArg2, ...>(TArg1 arg1, TArg2, ...);
             *
             */

            Logger.Debug($"Creating BeginMethod Dynamic Method for '{integrationType.FullName}' integration. [Target={targetType.FullName}]");
            var onMethodBeginMethodInfo = integrationType.GetMethod(BeginMethodName, BindingFlags.Public | BindingFlags.NonPublic | BindingFlags.Static);

            if (onMethodBeginMethodInfo is null)
            {
                Logger.Debug($"'{BeginMethodName}' method was not found in integration type: '{integrationType.FullName}'.");
                return(null);
            }

            if (onMethodBeginMethodInfo.ReturnType != typeof(CallTargetState))
            {
                throw new ArgumentException($"The return type of the method: {BeginMethodName} in type: {integrationType.FullName} is not {nameof(CallTargetState)}");
            }

            var genericArgumentsTypes = onMethodBeginMethodInfo.GetGenericArguments();

            if (genericArgumentsTypes.Length < 1)
            {
                throw new ArgumentException($"The method: {BeginMethodName} in type: {integrationType.FullName} doesn't have the generic type for the instance type.");
            }

            var onMethodBeginParameters = onMethodBeginMethodInfo.GetParameters();

            if (onMethodBeginParameters.Length < argumentsTypes.Length)
            {
                throw new ArgumentException($"The method: {BeginMethodName} with {onMethodBeginParameters.Length} parameters in type: {integrationType.FullName} has less parameters than required.");
            }
            else if (onMethodBeginParameters.Length > argumentsTypes.Length + 1)
            {
                throw new ArgumentException($"The method: {BeginMethodName} with {onMethodBeginParameters.Length} parameters in type: {integrationType.FullName} has more parameters than required.");
            }
            else if (onMethodBeginParameters.Length != argumentsTypes.Length && onMethodBeginParameters[0].ParameterType != genericArgumentsTypes[0])
            {
                throw new ArgumentException($"The first generic argument for method: {BeginMethodName} in type: {integrationType.FullName} must be the same as the first parameter for the instance value.");
            }

            var callGenericTypes = new List <Type>();

            var  mustLoadInstance          = onMethodBeginParameters.Length != argumentsTypes.Length;
            var  instanceGenericType       = genericArgumentsTypes[0];
            var  instanceGenericConstraint = instanceGenericType.GetGenericParameterConstraints().FirstOrDefault();
            Type instanceProxyType         = null;

            if (instanceGenericConstraint != null)
            {
                var result = DuckType.GetOrCreateProxyType(instanceGenericConstraint, targetType);
                instanceProxyType = result.ProxyType;
                callGenericTypes.Add(instanceProxyType);
            }
            else
            {
                callGenericTypes.Add(targetType);
            }

            var callMethod = new DynamicMethod(
                $"{onMethodBeginMethodInfo.DeclaringType.Name}.{onMethodBeginMethodInfo.Name}",
                typeof(CallTargetState),
                new Type[] { targetType }.Concat(argumentsTypes).ToArray(),
                onMethodBeginMethodInfo.Module,
                true);

            var ilWriter = callMethod.GetILGenerator();

            // Load the instance if is needed
            if (mustLoadInstance)
            {
                ilWriter.Emit(OpCodes.Ldarg_0);

                if (instanceGenericConstraint != null)
                {
                    WriteCreateNewProxyInstance(ilWriter, instanceProxyType, targetType);
                }
            }

            // Load arguments
            for (var i = mustLoadInstance ? 1 : 0; i < onMethodBeginParameters.Length; i++)
            {
                var  sourceParameterType           = argumentsTypes[mustLoadInstance ? i - 1 : i];
                var  targetParameterType           = onMethodBeginParameters[i].ParameterType;
                Type targetParameterTypeConstraint = null;
                Type parameterProxyType            = null;

                if (targetParameterType.IsGenericParameter)
                {
                    targetParameterType           = genericArgumentsTypes[targetParameterType.GenericParameterPosition];
                    targetParameterTypeConstraint = targetParameterType.GetGenericParameterConstraints().FirstOrDefault(pType => pType != typeof(IDuckType));
                    if (targetParameterTypeConstraint is null)
                    {
                        callGenericTypes.Add(sourceParameterType);
                    }
                    else
                    {
                        var result = DuckType.GetOrCreateProxyType(targetParameterTypeConstraint, sourceParameterType);
                        parameterProxyType = result.ProxyType;
                        callGenericTypes.Add(parameterProxyType);
                    }
                }
                else if (!targetParameterType.IsAssignableFrom(sourceParameterType) && (!(sourceParameterType.IsEnum && targetParameterType.IsEnum)))
                {
                    throw new InvalidCastException($"The target parameter {targetParameterType} can't be assigned from {sourceParameterType}");
                }

                WriteLoadArgument(ilWriter, i, mustLoadInstance);
                if (parameterProxyType != null)
                {
                    WriteCreateNewProxyInstance(ilWriter, parameterProxyType, sourceParameterType);
                }
            }

            // Call method
            onMethodBeginMethodInfo = onMethodBeginMethodInfo.MakeGenericMethod(callGenericTypes.ToArray());
            ilWriter.EmitCall(OpCodes.Call, onMethodBeginMethodInfo, null);
            ilWriter.Emit(OpCodes.Ret);

            Logger.Debug($"Created BeginMethod Dynamic Method for '{integrationType.FullName}' integration. [Target={targetType.FullName}]");
            return(callMethod);
        }