public bool Equals(MethodCallDelegateKey other)
            {
                if (ReferenceEquals(null, other))
                {
                    return(false);
                }
                if (other.hashCode != hashCode)
                {
                    return(false);
                }
                var otherItems = other.items;

                if (otherItems.Length != items.Length)
                {
                    return(false);
                }
                for (int i = 0; i < items.Length; i++)
                {
                    if (!Equals(otherItems[i], items[i]))
                    {
                        return(false);
                    }
                }
                return(true);
            }
        /// <summary>
        /// Creates property \ member setter delegate.
        /// </summary>
        /// <typeparam name="TObject">Declaring type.</typeparam>
        /// <typeparam name="TValue">Member type.</typeparam>
        /// <param name="memberName">Member name.</param>
        /// <returns><see cref="Action{T,R}"/> delegate
        /// that sets member value.</returns>
        public static Action <TObject, TValue> CreateSetMemberDelegate <TObject, TValue>(string memberName)
        {
            Type type      = typeof(TObject);
            Type tValue    = typeof(TValue);
            var  methodKey = new MethodCallDelegateKey(memberName, type, tValue);

            Action <TObject, TValue> result = (Action <TObject, TValue>)GetCachedDelegate(methodKey);

            if (result == null)
            {
                lock (cachedDelegates.SyncRoot) {
                    result = (Action <TObject, TValue>)GetCachedDelegate(methodKey);
                    if (result != null)
                    {
                        return(result);
                    }

                    PropertyInfo pi = type.GetProperty(memberName);
                    FieldInfo    fi = type.GetField(memberName);
                    if (pi != null)
                    {
                        // Member is a Property...
                        MethodInfo mi = pi.GetSetMethod(true);
                        if (mi != null)
                        {
                            //  Calling a property's get accessor is faster/cleaner using
                            //  Delegate.CreateDelegate rather than Reflection.Emit
                            // TODO: Check that type conversion is adequate.
                            result = (Action <TObject, TValue>)Delegate.CreateDelegate(typeof(Action <TObject, TValue>), mi);
                        }
                        else
                        {
                            throw new InvalidOperationException(string.Format(Strings.ExPropertyDoesNotHaveSetter,
                                                                              memberName, type.GetShortName()));
                        }
                    }
                    else if (fi != null)
                    {
                        // Member is a Field...
                        DynamicMethod dm = new DynamicMethod("Set" + memberName,
                                                             typeof(TValue), new Type[] { type }, type);
                        ILGenerator il = dm.GetILGenerator();
                        // Load the instance of the object (argument 0) onto the stack
                        il.Emit(OpCodes.Ldarg_0);
                        il.Emit(OpCodes.Ldarg_1);
                        // Load the value of the object's field (fi) onto the stack
                        il.Emit(OpCodes.Stfld, fi);
                        // return the value on the top of the stack
                        il.Emit(OpCodes.Ldc_I4_1);
                        il.Emit(OpCodes.Ret);

                        result = (Action <TObject, TValue>)dm.CreateDelegate(typeof(Func <TObject, TValue>));
                    }
                    else
                    {
                        throw new InvalidOperationException(string.Format(Strings.ExMemberIsNotPublicPropertyOrField,
                                                                          memberName, type.GetShortName()));
                    }
                    AddCachedDelegate(methodKey, result);
                }
            }
            return(result);
        }
        /// <summary>
        /// Creates primitive type cast delegate - e.g. <see cref="Enum"/> to <see cref="sbyte"/>.
        /// </summary>
        /// <typeparam name="TSource">The type to cast.</typeparam>
        /// <typeparam name="TTarget">Target type.</typeparam>
        /// <returns>A delegate allowing to cast <typeparamref name="TSource"/> to <typeparamref name="TTarget"/>.</returns>
        /// <exception cref="InvalidCastException"><c>InvalidCastException</c>.</exception>
        public static Converter <TSource, TTarget> CreatePrimitiveCastDelegate <TSource, TTarget>()
            where TSource : struct
            where TTarget : struct
        {
            Type   sourceType = typeof(TSource);
            Type   targetType = typeof(TTarget);
            string methodName = string.Format("{0}_{1}_{2}", primitiveCastMethodName, sourceType, targetType);
            var    methodKey  = new MethodCallDelegateKey(methodName);

            var result = GetCachedDelegate(methodKey) as Converter <TSource, TTarget>;

            if (result == null)
            {
                lock (cachedDelegates.SyncRoot) {
                    result = GetCachedDelegate(methodKey) as Converter <TSource, TTarget>;
                    if (result != null)
                    {
                        return(result);
                    }

                    Type actualSourceType = sourceType;
                    if (sourceType.IsEnum)
                    {
                        actualSourceType = Enum.GetUnderlyingType(sourceType);
                    }
                    if (!opCodeConv.ContainsKey(actualSourceType))
                    {
                        throw new InvalidCastException(string.Format(Strings.ExInvalidCast,
                                                                     sourceType.GetShortName(),
                                                                     targetType.GetShortName()));
                    }

                    Type actualTargetType = targetType;
                    if (targetType.IsEnum)
                    {
                        actualTargetType = Enum.GetUnderlyingType(targetType);
                    }
                    if (!opCodeConv.ContainsKey(actualTargetType))
                    {
                        throw new InvalidCastException(string.Format(Strings.ExInvalidCast,
                                                                     sourceType.GetShortName(),
                                                                     targetType.GetShortName()));
                    }

                    DynamicMethod dm = new DynamicMethod(methodName,
                                                         typeof(TTarget), new Type[] { sourceType });
                    ILGenerator il = dm.GetILGenerator();
                    il.Emit(OpCodes.Ldarg_0);

                    if (targetType.IsEnum)
                    {
                        if (typeOnStack[actualSourceType] != typeOnStack[actualSourceType])
                        {
                            il.Emit(opCodeConv[actualTargetType]);
                        }
                    }
                    il.Emit(OpCodes.Ret);
                    result = dm.CreateDelegate(typeof(Converter <TSource, TTarget>)) as Converter <TSource, TTarget>;

                    AddCachedDelegate(methodKey, result);
                }
            }
            return(result);
        }
        private static TDelegateType InnerCreateGetMemberDelegate <TObject, TValue, TDelegateType>(string memberName)
            where TDelegateType : class
        {
            Type type      = typeof(TObject);
            Type tValue    = typeof(TValue);
            var  methodKey = new MethodCallDelegateKey(typeof(TDelegateType), memberName, type, tValue);

            TDelegateType result = GetCachedDelegate(methodKey) as TDelegateType;

            if (result == null)
            {
                lock (cachedDelegates.SyncRoot) {
                    result = GetCachedDelegate(methodKey) as TDelegateType;
                    if (result != null)
                    {
                        return(result);
                    }

                    PropertyInfo pi = type.GetProperty(memberName);
                    FieldInfo    fi = type.GetField(memberName);
                    MethodInfo   smi;
                    if (pi != null)
                    {
                        // Member is a Property...
                        MethodInfo mi = pi.GetGetMethod(true);
                        if (mi != null)
                        {
                            //  Calling a property's get accessor is faster/cleaner using
                            //  Delegate.CreateDelegate rather than Reflection.Emit
                            result = Delegate.CreateDelegate(typeof(TDelegateType), mi) as TDelegateType;
                        }
                        else
                        {
                            throw new InvalidOperationException(string.Format(Strings.ExPropertyDoesNotHaveGetter,
                                                                              memberName, type.GetShortName()));
                        }
                    }
                    else if (fi != null)
                    {
                        // Member is a Field...
                        DynamicMethod dm = new DynamicMethod("Get" + memberName,
                                                             typeof(TValue), new Type[] { type }, type);
                        ILGenerator il = dm.GetILGenerator();
                        // Load the instance of the object (argument 0) onto the stack
                        il.Emit(OpCodes.Ldarg_0);
                        // Load the value of the object's field (fi) onto the stack
                        il.Emit(OpCodes.Ldfld, fi);
                        // return the value on the top of the stack
                        il.Emit(OpCodes.Ret);

                        result = dm.CreateDelegate(typeof(TDelegateType)) as TDelegateType;
                    }
                    else if (null != (smi = type.GetMethod(AspectedPrivateFieldGetterPrefix + memberName,
                                                           BindingFlags.Instance |
                                                           BindingFlags.Public |
                                                           BindingFlags.NonPublic |
                                                           BindingFlags.ExactBinding)))
                    {
                        result = Delegate.CreateDelegate(typeof(Func <TObject, TValue>), smi) as TDelegateType;
                    }
                    else
                    {
                        throw new InvalidOperationException(string.Format(Strings.ExMemberIsNotPublicPropertyOrField,
                                                                          memberName, type.GetShortName()));
                    }

                    AddCachedDelegate(methodKey, result as Delegate);
                }
            }
            return(result);
        }