/// <summary>
    ///     Gets the value of a content's property identified by its alias, converted to a specified type.
    /// </summary>
    /// <typeparam name="T">The target property type.</typeparam>
    /// <param name="content">The content.</param>
    /// <param name="publishedValueFallback">The published value fallback implementation.</param>
    /// <param name="alias">The property alias.</param>
    /// <param name="culture">The variation language.</param>
    /// <param name="segment">The variation segment.</param>
    /// <param name="fallback">Optional fallback strategy.</param>
    /// <param name="defaultValue">The default value.</param>
    /// <returns>The value of the content's property identified by the alias, converted to the specified type.</returns>
    /// <remarks>
    ///     <para>
    ///         The value comes from <c>IPublishedProperty</c> field <c>Value</c> ie it is suitable for use when rendering
    ///         content.
    ///     </para>
    ///     <para>
    ///         If no property with the specified alias exists, or if the property has no value, or if it could not be
    ///         converted, returns <c>default(T)</c>.
    ///     </para>
    ///     <para>
    ///         If eg a numeric property wants to default to 0 when value source is empty, this has to be done in the
    ///         converter.
    ///     </para>
    ///     <para>The alias is case-insensitive.</para>
    /// </remarks>
    public static T?Value <T>(
        this IPublishedElement content,
        IPublishedValueFallback publishedValueFallback,
        string alias,
        string?culture    = null,
        string?segment    = null,
        Fallback fallback = default,
        T?defaultValue    = default)
    {
        IPublishedProperty?property = content.GetProperty(alias);

        // if we have a property, and it has a value, return that value
        if (property != null && property.HasValue(culture, segment))
        {
            return(property.Value <T>(publishedValueFallback, culture, segment));
        }

        // else let fallback try to get a value
        if (publishedValueFallback.TryGetValue(content, alias, culture, segment, fallback, defaultValue, out T? value))
        {
            return(value);
        }

        // else... if we have a property, at least let the converter return its own
        // vision of 'no value' (could be an empty enumerable) - otherwise, default
        return(property == null ? default : property.Value <T>(publishedValueFallback, culture, segment));
    }
    public static object?Value(this IPublishedProperty property, IPublishedValueFallback publishedValueFallback, string?culture = null, string?segment = null, Fallback fallback = default, object?defaultValue = default)
    {
        if (property.HasValue(culture, segment))
        {
            return(property.GetValue(culture, segment));
        }

        return(publishedValueFallback.TryGetValue(property, culture, segment, fallback, defaultValue, out var value)
            ? value
            : property.GetValue(culture, segment)); // give converter a chance to return it's own vision of "no value"
    }