internal static InstanceItemHookFactory From <TRequest, TItem>(
     IItemHook <TRequest, TItem> hook)
 {
     return(new InstanceItemHookFactory(
                hook,
                new FunctionItemHook((request, item, ct)
                                     => hook.Run((TRequest)request, (TItem)item, ct).ContinueWith(t => (object)t.Result))));
 }
        public CrudBulkRequestEntityConfigBuilder <TRequest, TItem, TEntity> AddItemHook <TBaseRequest>(
            IItemHook <TBaseRequest, TItem> hook)
        {
            if (!typeof(TBaseRequest).IsAssignableFrom(typeof(TRequest)))
            {
                throw new ContravarianceException(nameof(AddItemHook), typeof(TBaseRequest), typeof(TRequest));
            }

            _itemHooks.Add(InstanceItemHookFactory.From(hook));

            return(this);
        }
        /// <summary>
        /// Adds an item hook instance.
        /// </summary>
        public BulkRequestEntityConfigBuilder <TRequest, TItem, TEntity> AddItemHook(IItemHook hook)
        {
            var hookType = hook.GetType();

            var baseHookType = hookType
                               .GetBaseTypes()
                               .SingleOrDefault(x =>
                                                x.IsGenericType && x.GetGenericTypeDefinition() == typeof(ItemHook <,>));

            if (baseHookType == null)
            {
                throw new ArgumentException($"Unable to add '{hookType}' as an item hook for '{typeof(TRequest)}'.\r\n" +
                                            $"Item hooks must inherit ItemHook<TRequest, TItem>.");
            }

            var requestType = baseHookType.GenericTypeArguments[0];

            if (!requestType.IsAssignableFrom(typeof(TRequest)))
            {
                throw new ContravarianceException(nameof(AddItemHook), requestType, typeof(TRequest));
            }

            var itemType = baseHookType.GenericTypeArguments[1];

            if (!itemType.IsAssignableFrom(typeof(TItem)))
            {
                throw new ContravarianceException(nameof(AddItemHook), itemType, typeof(TItem));
            }

            var factoryMethod = typeof(InstanceItemHookFactory)
                                .GetMethod(nameof(InstanceItemHookFactory.From), BindingFlags.NonPublic | BindingFlags.Static)
                                .MakeGenericMethod(requestType, itemType);

            try
            {
                return(AddItemHook((IItemHookFactory)factoryMethod.Invoke(null, new object[] { hook })));
            }
            catch (TargetInvocationException e)
            {
                if (e.InnerException != null)
                {
                    throw e.InnerException;
                }

                throw e;
            }
        }