internal ForEachExpression(
            ParameterExpression variable,
            Expression enumerable,
            Expression body,
            LabelTarget?breakTarget,
            LabelTarget?continueTarget)
        {
            _enumerableTypeDescriptor = EnumerableTypeDescriptor.GetTypeDescriptor(enumerable.Type);

            if (!_enumerableTypeDescriptor.IsEnumerable)
            {
                throw new ArgumentException("The specified argument is not enumerable.", nameof(enumerable));
            }

            Variable       = variable;
            Enumerable     = enumerable;
            Body           = body;
            BreakTarget    = breakTarget ?? Expression.Label("break");
            ContinueTarget = continueTarget ?? Expression.Label("continue");
        }
        public static IEnumerable CloneTo(this IEnumerable enumerable, Type typeToBuild)
        {
            if (typeToBuild is null)
            {
                throw new ArgumentNullException(nameof(typeToBuild));
            }

            var enumerableTypeDescriptor = EnumerableTypeDescriptor.Get(typeToBuild);

            if (!enumerableTypeDescriptor.IsEnumerable)
            {
                throw new ArgumentException(nameof(typeToBuild), $"Type {typeToBuild.Name} is not an IEnumerable type.");
            }

            if (enumerable is null)
            {
                if (typeToBuild.IsArrayOrArrayClass())
                {
                    return(Array.CreateInstance(enumerableTypeDescriptor.ExplicitImplementation.ElementType, 0));
                }

                if (enumerableTypeDescriptor.ParameterlessConstructor is null)
                {
                    throw new InvalidOperationException($"Cannot create enumerable of type {typeToBuild.Name}. The type does not provide a parameterless constructor.");
                }

                return((IEnumerable)enumerableTypeDescriptor.ParameterlessConstructor.Invoke());
            }

            if (typeToBuild.IsArrayOrArrayClass())
            {
                return(enumerable.DynamicToArray(enumerableTypeDescriptor.ExplicitImplementation.ElementType));
            }

            var ctor = enumerableTypeDescriptor.ConstructorsWithEnumerableParameter
                       .Where(x => x.Key.IsInstanceOfType(enumerable))
                       .Select(x => x.Value)
                       .FirstOrDefault();

            if (ctor != null)
            {
                return((IEnumerable)ctor.Invoke(enumerable));
            }

            if (enumerableTypeDescriptor.ParameterlessConstructor == null)
            {
                throw new InvalidOperationException($"Cannot create enumerable of type {typeToBuild.Name} from data of type {enumerable.GetType().Name}. The type does not provide a proper constructor with a single parameter for data, nor a parameterless constructor.");
            }

            var instance = (IEnumerable)enumerableTypeDescriptor.ParameterlessConstructor.Invoke();

            if (enumerableTypeDescriptor.ExplicitImplementation.Kind == EnumerableInterfaceKind.Dictionary)
            {
                foreach (var item in enumerable)
                {
                    var entry = GetKeyValuePair(item);

                    var addMethod = enumerableTypeDescriptor.GetApplicableDictionaryMethod(DictionaryMethod.Add, entry);
                    if (addMethod == null)
                    {
                        throw new InvalidOperationException($"Cannot add element of type {item?.GetType()} to dictionary of type {instance.GetType()}. No applicable Add method was found on the type");
                    }

                    addMethod.MethodInfoEx.Invoke(instance, entry.key, entry.value);
                }
            }
            else
            {
                var index = 0;
                foreach (var item in enumerable)
                {
                    var applicableMethod =
                        enumerableTypeDescriptor.GetApplicableListMethod(ListMethod.Add, item) ??
                        enumerableTypeDescriptor.GetApplicableListMethod(ListMethod.Insert, item);
                    if (applicableMethod is null)
                    {
                        throw new InvalidOperationException($"Cannot add element of type {item?.GetType()} to collection of type {instance.GetType()}. No applicable Add or Insert methods were found on the type");
                    }
                    else
                    {
                        try
                        {
                            if (applicableMethod.Method == ListMethod.Add)
                            {
                                applicableMethod.MethodInfoEx.Invoke(instance, item);
                            }
                            else
                            {
                                applicableMethod.MethodInfoEx.Invoke(instance, index, item);
                            }
                        }
                        catch (Exception e)
                        {
                            throw new InvalidOperationException($"Cannot add element of type {item?.GetType()} to collection of type {instance.GetType()}. No applicable Add or Insert method was found on the type or the applicable method failed (see inner exception).", e);
                        }
                    }
                    index++;
                }
            }

            return(instance);
        }