/// <summary>
        /// Creates a function that gets the value of the specified property. The parameter of the
        /// resulting function takes the object whose property value is to be accessed. If the
        /// specified property is static, the parameter of the resulting function is ignored.
        /// </summary>
        /// <param name="property">The property to create the getter function for.</param>
        /// <returns>A function that gets the property value.</returns>
        public static Func <object, object> CreateGetter(this PropertyInfo property)
        {
            if (property == null)
            {
                throw new ArgumentNullException(nameof(property));
            }
            if (!property.CanRead || !property.GetMethod.IsPublic)
            {
                throw new ArgumentException("Property must have public getter.", nameof(property));
            }

            var getter = new PropertyGetter(property);

            QueueUserWorkItem(getter, g => g.SetOptimizedFunc());
            return(getter.GetValue);
        }
        /// <summary>
        /// Creates a function that gets the value of the specified property. The parameter of the
        /// resulting function takes the object whose property value is to be accessed. If the
        /// specified property is static, the parameter of the resulting function is ignored.
        /// </summary>
        /// <typeparam name="TPropertyType">
        /// The return type of the resulting function. 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 getter function for.</param>
        /// <returns>A function that gets the property value.</returns>
        public static Func <object, TPropertyType> CreateGetter <TPropertyType>(this PropertyInfo property)
        {
            if (property == null)
            {
                throw new ArgumentNullException(nameof(property));
            }
            if (!typeof(TPropertyType).IsAssignableFrom(property.PropertyType))
            {
                throw new ArgumentException("TPropertyType must be assignable from property.PropertyType", nameof(property));
            }
            if (!property.CanRead || !property.GetMethod.IsPublic)
            {
                throw new ArgumentException("property must have public getter", nameof(property));
            }

            var getter = new PropertyGetter <TPropertyType>(property);

            QueueUserWorkItem(getter, g => g.SetOptimizedFunc());
            return(getter.GetValue);
        }