/// <summary>
        /// Get value.
        /// </summary>
        /// <param name="valueProvider">The <see cref="IPopulaterValueProvider"/>.</param>
        /// <param name="type">The value type.</param>
        /// <param name="prefix">Prefix for string values.</param>
        /// <param name="depth">Depth of value within object hierarchy.</param>
        /// <returns>The value.</returns>
        protected object GetValue(IPopulaterValueProvider valueProvider, Type type, string prefix, int depth)
        {
            object   value    = null;
            TypeInfo typeInfo = type.GetTypeInfo();

            if (_generatorDictionary.ContainsKey(type))
            {
                value = _generatorDictionary[type](valueProvider, prefix);
            }
            else if (typeInfo.IsArray)
            {
                value = GetArray(valueProvider, type.GetElementType(), prefix, depth + 1);
            }
            else if (_iListTypeInfo.IsAssignableFrom(type))
            {
                value = GetList(valueProvider, typeInfo, prefix, depth + 1);
            }
            else if (_iEnumerableTypeInfo.IsAssignableFrom(type))
            {
                value = GetIEnumerable(valueProvider, typeInfo, prefix, depth + 1);
            }
            else if (typeInfo.IsClass)
            {
                value = GetClassInstance(valueProvider, type, depth + 1);
            }
            else if (typeInfo.IsEnum)
            {
                value = valueProvider.GetEnum(type);
            }

            return(value);
        }
        /// <summary>
        /// Populate existing instance of <typeparamref name="T"/> with test data.
        /// </summary>
        /// <typeparam name="T">The class type.</typeparam>
        /// <param name="instance">The instance of <typeparamref name="T"/>.</param>
        /// <param name="valueProvider">The <see cref="IPopulaterValueProvider"/>
        /// (defaults to <see cref="SequentialValueProvider"/>.</param>
        /// <returns>The populated <typeparamref name="T"/> instance.</returns>
        public virtual T Populate <T>(T instance, IPopulaterValueProvider valueProvider = null)
        {
            valueProvider = valueProvider ?? new SequentialValueProvider();

            int depth = 1;

            Populate(instance, valueProvider, typeof(T).GetTypeInfo(), depth);

            return(instance);
        }
        /// <summary>
        /// Create new instance of <typeparamref name="T"/> and populate with test data.
        /// </summary>
        /// <typeparam name="T">The class type.</typeparam>
        /// <param name="valueProvider">The <see cref="IPopulaterValueProvider"/>
        /// (defaults to <see cref="SequentialValueProvider"/>).</param>
        /// <returns>The created and populated instance of <typeparamref name="T"/>.</returns>
        public virtual T CreateAndPopulate <T>(IPopulaterValueProvider valueProvider = null)
        {
            Type type = typeof(T);

            if (_generatorDictionary.ContainsKey(type))
            {
                valueProvider = valueProvider ?? new SequentialValueProvider();
                return((T)_generatorDictionary[type].Invoke(valueProvider, ""));
            }
            ;

            return(Populate((T)Activator.CreateInstance(typeof(T)), valueProvider));
        }
        private object GetIEnumerable(IPopulaterValueProvider valueProvider, TypeInfo typeInfo, string prefix, int depth)
        {
            Array array = null;

            Type[] types = typeInfo.GetGenericArguments();

            if (types.Length == 1)
            {
                array = GetArray(valueProvider, types[0], prefix, depth);
            }

            return(array);
        }
        private void Populate(object instance, IPopulaterValueProvider valueProvider, TypeInfo typeInfo, int depth)
        {
            PropertyInfo[] publicReadWriterProperties = typeInfo
                                                        .GetProperties(BindingFlags.Public | BindingFlags.Instance)
                                                        .Where(propertyInfo => propertyInfo.CanRead && propertyInfo.CanWrite)
                                                        .ToArray();

            foreach (PropertyInfo property in publicReadWriterProperties)
            {
                object value = GetValue(valueProvider, property.PropertyType, property.Name, depth);

                if (value != null)
                {
                    property.SetValue(instance, value, null);
                }
            }
        }
        private object GetClassInstance(IPopulaterValueProvider valueProvider, Type type, int depth)
        {
            if (MaximumDepth < depth)
            {
                return(null);
            }

            object value = null;

            value = TryToCreateInstance(type, () => Activator.CreateInstance(type));

            if (value != null)
            {
                Populate(value, valueProvider, type.GetTypeInfo(), depth);
            }

            return(value);
        }
        private object GetList(IPopulaterValueProvider valueProvider, TypeInfo typeInfo, string prefix, int depth)
        {
            object list = null;

            Type[] genericArguments = typeInfo.GetGenericArguments();

            if (genericArguments.Length == 1)
            {
                Array array = GetArray(valueProvider, genericArguments[0], prefix, depth);

                if (array != null)
                {
                    Type genericListType = typeof(List <>).MakeGenericType(genericArguments);

                    TryToCreateInstance(genericListType, () => list = Activator.CreateInstance(genericListType, array));
                }
            }

            return(list);
        }
        private Array GetArray(IPopulaterValueProvider valueProvider, Type type, string prefix, int depth)
        {
            Array array = null;

            if (type != null)
            {
                int itemCount = valueProvider.GetEnumerableSize();

                array = TryToCreateInstance(type, () => Array.CreateInstance(type, itemCount)) as Array;

                if (array != null)
                {
                    for (int i = 0; i < itemCount; i++)
                    {
                        string childPrefix = $"{prefix}[{i}]";
                        var    item        = GetValue(valueProvider, type, childPrefix, depth);
                        array.SetValue(item, i);
                    }
                }
            }

            return(array);
        }
 private static object GetUShort(IPopulaterValueProvider valueProvider, string _) => valueProvider.GetUShort();
 private static object GetString(IPopulaterValueProvider valueProvider, string prefix) => valueProvider.GetString(prefix);
 private static object GetSByte(IPopulaterValueProvider valueProvider, string _) => valueProvider.GetSByte();
 private static object GetDecimal(IPopulaterValueProvider valueProvider, string _) => valueProvider.GetDecimal();
 private static object GetByteArray(IPopulaterValueProvider valueProvider, string _) => valueProvider.GetByteArray();
        /// <summary>
        /// Create <see cref="IEnumerable{T}"/> and populate with test data.
        /// </summary>
        /// <typeparam name="T">The class type.</typeparam>
        /// <param name="count">The desired <see cref="IEnumerable{T}"/> count.</param>
        /// <param name="valueProvider">The <see cref="IPopulaterValueProvider"/>
        /// (defaults to <see cref="SequentialValueProvider"/>).</param>
        /// <returns>The created and populated instance of <typeparamref name="T"/>.</returns>
        public virtual IEnumerable <T> CreateIEnumerableOf <T>(int count, IPopulaterValueProvider valueProvider = null)
        {
            valueProvider = valueProvider ?? new SequentialValueProvider();

            return(Enumerable.Range(1, count).Select(_ => CreateAndPopulate <T>(valueProvider)));
        }