dotnet / command-line-api

Command line parsing, invocation, and rendering of terminal output.
https://github.com/dotnet/command-line-api/wiki
MIT License
3.34k stars 375 forks source link

Consider adding value AnnotationAccessors #2403

Open KathleenDollard opened 2 months ago

KathleenDollard commented 2 months ago

Value annotation accessors would do two things:

And example is default values which are stored as object?

While it would be nice to store the specific value, rather than the general one, I do not see a way that is possible. However, I think the code below would solve the two problems above:

public struct ValueAnnotationAccessor<TValue>(CliSubsystem owner, AnnotationId<TValue> id)
{
    /// <summary>
    /// The ID of the annotation
    /// </summary>
    public AnnotationId<TValue> Id { get; }
    public readonly void Set<TSymbolValue>(CliOption<TSymbolValue> symbol, TSymbolValue value)
        where TSymbolValue : TValue
        => owner.SetAnnotation(symbol, id, value);
    public readonly void Set<TSymbolValue>(CliArgument<TSymbolValue> symbol, TSymbolValue value)
        where TSymbolValue : TValue
        => owner.SetAnnotation(symbol, id, value); 
    public readonly bool TryGet(CliSymbol symbol, [NotNullWhen(true)] out TValue? value) => owner.TryGetAnnotation(symbol, id, out value);
}

If we wish this to be polymorphic with other AnnotationAccessors, it could derive from it, in which case it could also drop SetAnnotation

KalleOlaviNiemitalo commented 2 months ago

AnnotationId\<TValue> looks similar to HttpRequestOptionsKey\<TValue>.

And now I realize it has already been implemented and just doesn't show up in GitHub code search because that doesn't cover non-default branches.

KalleOlaviNiemitalo commented 2 months ago

[NotNullWhen(true)] out TValue? value seems strange. What if I have a nullable type (e.g. string?) as TValue and store null, and then query with TryGet; does that assign value = null and return true, thus claiming that value is not null after all? I imagine this should instead be [MaybeNullWhen(false)] out TValue value, like in Dictionary\<TKey, TValue>.TryGetValue.