StronglyTypedDictionaryGenerator 1.0.8

There is a newer version of this package available.
See the version list below for details.
dotnet add package StronglyTypedDictionaryGenerator --version 1.0.8                
NuGet\Install-Package StronglyTypedDictionaryGenerator -Version 1.0.8                
This command is intended to be used within the Package Manager Console in Visual Studio, as it uses the NuGet module's version of Install-Package.
<PackageReference Include="StronglyTypedDictionaryGenerator" Version="1.0.8" />                
For projects that support PackageReference, copy this XML node into the project file to reference the package.
paket add StronglyTypedDictionaryGenerator --version 1.0.8                
#r "nuget: StronglyTypedDictionaryGenerator, 1.0.8"                
#r directive can be used in F# Interactive and Polyglot Notebooks. Copy this into the interactive tool or source code of the script to reference the package.
// Install StronglyTypedDictionaryGenerator as a Cake Addin
#addin nuget:?package=StronglyTypedDictionaryGenerator&version=1.0.8

// Install StronglyTypedDictionaryGenerator as a Cake Tool
#tool nuget:?package=StronglyTypedDictionaryGenerator&version=1.0.8                

StronglyTypedDictionaryGenerator

Roslyn powered source generator for strongly typed dictionaries.

Easily turn an interface into a strongly typed dictionary. Use it for persisting data, interop, serialization, config files, etc.

Generated source

Sample user defined input:
interface IMyInterface
{
    [System.ComponentModel.DefaultValue(69)]
    int Property1 { get; set; }

    bool Property2 { get; set; }

    [System.ComponentModel.DefaultValue(true)]
    bool Property3 { get; set; }

    [System.ComponentModel.DefaultValue("Hello Roslyn!")]
    string Property4 { get; set; }

    CultureInfo Property5 { get; set; }
}

[StronglyTypedDictionary(targetType: typeof(IMyInterface), supportsDefaultValues: true)]
internal partial class MyStronglyTypedDictionary : IMyInterface
{
    private bool someCondition;

    protected override T GetOrDefault<T>(T defaultValue, [CallerMemberName] string name = null!)
    {
        switch (name)
        {
            case nameof(IMyInterface.Property3) when someCondition:
                defaultValue = (T)(object)false;
                break;
            default:
                break;
        }

        return base.GetOrDefault(defaultValue, name);
    }

    public CultureInfo Property5
    {
        get => CultureInfo.GetCultureInfo(Get());
        set => Set(value.Name);
    }
}
Sample generated output:
internal partial class MyStronglyTypedDictionary : GeneratedBase<global::Demo.IMyInterface>, global::Demo.IMyInterface
{
    public MyStronglyTypedDictionary(IStronglyTypedKeyValuePairAccessor stronglyTypedKeyValuePairAccessor) : base(stronglyTypedKeyValuePairAccessor)
    {
    }

    public MyStronglyTypedDictionary(global::System.Collections.Generic.IDictionary<string, object> dictionary) : base(dictionary)
    {
    }

    public int Property1
    {
        get => GetOrDefault<int>(69);
        set => Set(value);
    }
    public bool Property2
    {
        get => Get<bool>();
        set => Set(value);
    }
    public bool Property3
    {
        get => GetOrDefault<bool>(true);
        set => Set(value);
    }
    public string Property4
    {
        get => GetOrDefault("Hello Roslyn!");
        set => Set(value);
    }
}

public abstract class GeneratedBase
{
    private sealed class StronglyTypedKvpWrapper : IStronglyTypedKeyValuePairAccessor
    {
        private readonly global::System.Collections.Generic.IDictionary<string, object> dictionary;

        public StronglyTypedKvpWrapper(global::System.Collections.Generic.IDictionary<string, object> dictionary)
        {
            this.dictionary = dictionary;
        }

        public T Get<T>(string name) where T : unmanaged
        {
            return (T)dictionary[name];
        }

        public string Get(string name)
        {
            return (string)dictionary[name];
        }

        public bool TryGet<T>(string name, out T value) where T : unmanaged
        {
            var result = dictionary.TryGetValue(name, out object? v);
            value = v is not null ? (T)v : default;
            return result;
        }

        public bool TryGet(string name, [global::System.Diagnostics.CodeAnalysis.NotNullWhen(true)] out string? value)
        {
            var result = dictionary.TryGetValue(name, out object? v);
            value = (string?)v;
            return result;
        }

        public void Set<T>(string name, T value) where T : unmanaged
        {
            dictionary[name] = value;
        }

        public void Set(string name, string value)
        {
            dictionary[name] = value;
        }
    }

    private readonly IStronglyTypedKeyValuePairAccessor stronglyTypedKeyValuePairAccessor;

    private protected GeneratedBase(IStronglyTypedKeyValuePairAccessor stronglyTypedKeyValuePairAccessor)
    {
        this.stronglyTypedKeyValuePairAccessor = stronglyTypedKeyValuePairAccessor;
    }

    private protected GeneratedBase(global::System.Collections.Generic.IDictionary<string, object> dictionary)
        : this(new StronglyTypedKvpWrapper(dictionary))
    {

    }

    protected T Get<T>([global::System.Runtime.CompilerServices.CallerMemberName] string name = null!) where T : unmanaged
    {
        return stronglyTypedKeyValuePairAccessor.Get<T>(name);
    }

    protected string Get([global::System.Runtime.CompilerServices.CallerMemberName] string name = null!)
    {
        return stronglyTypedKeyValuePairAccessor.Get(name);
    }

    [global::System.Runtime.CompilerServices.MethodImpl(global::System.Runtime.CompilerServices.MethodImplOptions.AggressiveInlining)]
    protected virtual T GetOrDefault<T>(T defaultValue, [global::System.Runtime.CompilerServices.CallerMemberName] string name = null!) where T : unmanaged
    {
        return stronglyTypedKeyValuePairAccessor.TryGet(name, out T result) ? result : defaultValue;
    }

    [global::System.Runtime.CompilerServices.MethodImpl(global::System.Runtime.CompilerServices.MethodImplOptions.AggressiveInlining)]
    protected virtual string GetOrDefault(string defaultValue, [global::System.Runtime.CompilerServices.CallerMemberName] string name = null!)
    {
        return stronglyTypedKeyValuePairAccessor.TryGet(name, out string? result) ? result : defaultValue;
    }

    protected void Set<T>(T value, [global::System.Runtime.CompilerServices.CallerMemberName] string name = null!) where T : unmanaged
    {
        stronglyTypedKeyValuePairAccessor.Set(name, value);
    }

    protected void Set(string value, [global::System.Runtime.CompilerServices.CallerMemberName] string name = null!)
    {
        stronglyTypedKeyValuePairAccessor.Set(name, value);
    }
}

public abstract class GeneratedBase<TInterface> : GeneratedBase
{
    private protected GeneratedBase(IStronglyTypedKeyValuePairAccessor stronglyTypedKeyValuePairAccessor) : base(stronglyTypedKeyValuePairAccessor)
    {
    }

    private protected GeneratedBase(global::System.Collections.Generic.IDictionary<string, object> dictionary) : base(dictionary)
    {
    }

    public TProperty Get<TProperty>(global::System.Linq.Expressions.Expression<Func<TInterface, TProperty>> expression)
        where TProperty : unmanaged
    {
        return base.Get<TProperty>(GetMemberName(expression));
    }

    public string Get(global::System.Linq.Expressions.Expression<Func<TInterface, string>> expression)
    {
        return base.Get(GetMemberName(expression));
    }

    public void Set<TProperty>(global::System.Linq.Expressions.Expression<Func<TInterface, TProperty>> expression, TProperty value)
        where TProperty : unmanaged
    {
        base.Set<TProperty>(value, GetMemberName(expression));
    }

    public void Set(global::System.Linq.Expressions.Expression<Func<TInterface, string>> expression, string value)
    {
        base.Set(value, GetMemberName(expression));
    }

    private static string GetMemberName<TProperty>(global::System.Linq.Expressions.Expression<Func<TInterface, TProperty>> expression)
    {
        return expression.Body switch
        {
            global::System.Linq.Expressions.MemberExpression m => m.Member.Name,
            global::System.Linq.Expressions.UnaryExpression u when u.Operand is global::System.Linq.Expressions.MemberExpression m => m.Member.Name,
            _ => throw new global::System.NotImplementedException($"Invalid expression: {expression.GetType()}. Exprected accessor."),
        };
    }
}
There are no supported framework assets in this package.

Learn more about Target Frameworks and .NET Standard.

  • .NETStandard 2.0

    • No dependencies.

NuGet packages

This package is not used by any NuGet packages.

GitHub repositories

This package is not used by any popular GitHub repositories.

Version Downloads Last updated
2.0.3 247 12/4/2023
1.1.8 467 2/28/2022
1.0.8 253 12/27/2021
1.0.7 250 12/27/2021
1.0.5 275 12/26/2021