/// <summary>
        /// Copies values from the source into the properties of the target.
        /// </summary>
        /// <param name="source">An object containing the source values.</param>
        /// <param name="target">An object with properties to be set from the source.</param>
        /// <param name="settings">The settings to use when copying properties.</param>
        /// <remarks>
        ///     <para>
        /// The property names and types of the source object must match the property names and types
        /// on the target object. Source properties may not be indexed.
        /// Target properties may not be readonly or indexed.
        /// </para><para>
        /// Properties to copy are determined based on the source object. Any properties
        /// on the source object marked with the <see cref="BrowsableAttribute"/> equal
        /// to false are ignored.
        /// </para>
        /// </remarks>
        public static void Copy(object source, object target, ObjectCopierSettings settings)
        {
            if (source == null)
            {
                throw new ArgumentNullException("source", "Source object can not be Null.");
            }
            if (target == null)
            {
                throw new ArgumentNullException("target", "Target object can not be Null.");
            }

            if (settings == null)
            {
                settings = new ObjectCopierSettings();
            }

            string[] sourceProperties;
            if (settings.UseDynamicCache)
            {
                sourceProperties = MethodCaller.GetCachedPropertyNames(source.GetType());
            }
            else
            {
                sourceProperties = MethodCaller.GetPropertyNames(source.GetType());
            }

            foreach (string propertyName in sourceProperties)
            {
                if (settings.IgnoreList.Contains(propertyName))
                {
                    continue;
                }

                try
                {
                    object value = GetPropertyValue(source, propertyName, settings.UseDynamicCache);
                    SetPropertyValue(target, propertyName, value, settings.UseDynamicCache);
                }
                catch (Exception ex)
                {
                    Debug.WriteLine(String.Format("Property '{0}' copy failed.", propertyName));
                    if (!settings.SuppressExceptions)
                    {
                        throw new InvalidOperationException(
                                  String.Format("Property '{0}' copy failed.", propertyName), ex);
                    }
                }
            }
        }
        /// <summary>
        /// Gets an object's property value by name.
        /// </summary>
        /// <param name="target">Object containing the property to get.</param>
        /// <param name="propertyName">Name of the property.</param>
        /// <param name="useCache">if set to <c>true</c> use dynamic cache.</param>
        /// <returns>The value of the property.</returns>
        public static object GetPropertyValue(object target, string propertyName, bool useCache)
        {
            if (target == null)
            {
                throw new ArgumentNullException("target");
            }
            if (String.IsNullOrEmpty(propertyName))
            {
                throw new ArgumentNullException("propertyName");
            }

            if (useCache)
            {
                DynamicMemberHandle handle = MethodCaller.GetCachedProperty(target.GetType(), propertyName);
                return(handle.DynamicMemberGet(target));
            }

            PropertyInfo propertyInfo = MethodCaller.FindProperty(target.GetType(), propertyName);

            return(propertyInfo.GetValue(target, null));
        }
        /// <summary>
        /// Sets an object's property with the specified value,
        /// converting that value to the appropriate type if possible.
        /// </summary>
        /// <param name="target">Object containing the property to set.</param>
        /// <param name="propertyName">Name of the property to set.</param>
        /// <param name="value">Value to set into the property.</param>
        /// <param name="useCache">if set to <c>true</c> use dynamic cache.</param>
        public static void SetPropertyValue(object target, string propertyName, object value, bool useCache)
        {
            if (target == null)
            {
                throw new ArgumentNullException("target", "Target object can not be Null.");
            }

            if (useCache)
            {
                DynamicMemberHandle handle = MethodCaller.GetCachedProperty(target.GetType(), propertyName);
                if (handle != null)
                {
                    SetValueWithCoercion(target, handle, value);
                }
            }
            else
            {
                PropertyInfo propertyInfo = MethodCaller.FindProperty(target.GetType(), propertyName);
                if (propertyInfo != null)
                {
                    SetValueWithCoercion(target, propertyInfo, value);
                }
            }
        }
 /// <summary>
 /// Finds a <see cref="PropertyInfo"/> by name ignoring case.
 /// </summary>
 /// <param name="type">The type to search.</param>
 /// <param name="propertyName">Name of the property.</param>
 /// <returns>A <see cref="PropertyInfo"/> matching the property name.</returns>
 /// <remarks>
 /// FindProperty will first try to get a property matching the name and case of the
 /// property name specified.  If a property cannot be found, all the properties will
 /// be searched ignoring the case of the name.
 /// </remarks>
 public static PropertyInfo FindProperty(Type type, string propertyName)
 {
     return(MethodCaller.FindProperty(type, propertyName));
 }