/// <summary>
        /// Creates an action that sets the value of the specified property. The first parameter
        /// of the resulting function takes the object whose property value is to be set. If the
        /// specified property is static, the first parameter of the resulting function is ignored.
        /// The second parameter of the resulting function takes the new value of the property.
        /// </summary>
        /// <param name="property">The property to create the setter action for.</param>
        /// <returns>An action that sets the property value.</returns>
        public static Action <object, object> CreateSetter(this PropertyInfo property)
        {
            if (property == null)
            {
                throw new ArgumentNullException(nameof(property));
            }
            if (!property.CanWrite || !property.SetMethod.IsPublic)
            {
                throw new ArgumentException("property must have public setter", nameof(property));
            }

            var setter = new PropertySetter(property);

            QueueUserWorkItem(setter, s => s.SetOptimizedAction());
            return(setter.SetValue);
        }
        /// <summary>
        /// Creates an action that sets the value of the specified property. The first parameter
        /// of the resulting function takes the object whose property value is to be set. If the
        /// specified property is static, the first parameter of the resulting function is ignored.
        /// The second parameter of the resulting function takes the new value of the property.
        /// </summary>
        /// <typeparam name="TPropertyType">
        /// The type of the second parameter of the resulting action. This type must be compatible with
        /// the <see cref="PropertyInfo.PropertyType"/> of the <paramref name="property"/> parameter.
        /// </typeparam>
        /// <param name="property">The property to create the setter action for.</param>
        /// <returns>An action that sets the property value.</returns>
        public static Action <object, TPropertyType> CreateSetter <TPropertyType>(this PropertyInfo property)
        {
            if (property == null)
            {
                throw new ArgumentNullException(nameof(property));
            }
            if (!property.PropertyType.IsAssignableFrom(typeof(TPropertyType)))
            {
                throw new ArgumentException("property.PropertyType must be assignable from TPropertyType", nameof(property));
            }
            if (!property.CanWrite || !property.SetMethod.IsPublic)
            {
                throw new ArgumentException("property must have public setter", nameof(property));
            }

            var setter = new PropertySetter <TPropertyType>(property);

            QueueUserWorkItem(setter, s => s.SetOptimizedAction());
            return(setter.SetValue);
        }