An open API service indexing awesome lists of open source software.

https://github.com/trympet/stronglytypeddictionarygenerator

Roslyn powered source generator for creating dictionaries backed by a strongly typed interface.
https://github.com/trympet/stronglytypeddictionarygenerator

component-model cross-platform csharp csharp-sourcegenerator roslyn source-generator

Last synced: 9 months ago
JSON representation

Roslyn powered source generator for creating dictionaries backed by a strongly typed interface.

Awesome Lists containing this project

README

          

# 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:
```csharp
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; }

[System.ComponentModel.DefaultValue(null)]
TimeSpan Property6 { get; set; }
}

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

protected override T GetOrDefault(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:
```csharp
internal partial class MyStronglyTypedDictionary : GeneratedBase, global::Demo.IMyInterface
{
public MyStronglyTypedDictionary(IStronglyTypedKeyValuePairAccessor stronglyTypedKeyValuePairAccessor) : base(stronglyTypedKeyValuePairAccessor)
{
}

public MyStronglyTypedDictionary(global::System.Collections.Generic.IDictionary dictionary) : base(dictionary)
{
}

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

public abstract class GeneratedBase
{
private sealed class StronglyTypedKvpWrapper : IStronglyTypedKeyValuePairAccessor
{
private readonly global::System.Collections.Generic.IDictionary dictionary;

public StronglyTypedKvpWrapper(global::System.Collections.Generic.IDictionary dictionary)
{
this.dictionary = dictionary;
}

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

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

public bool TryGet(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(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 dictionary)
: this(new StronglyTypedKvpWrapper(dictionary))
{

}

protected T Get([global::System.Runtime.CompilerServices.CallerMemberName] string name = null!) where T : unmanaged
{
return stronglyTypedKeyValuePairAccessor.Get(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 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 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 : GeneratedBase
{
private protected GeneratedBase(IStronglyTypedKeyValuePairAccessor stronglyTypedKeyValuePairAccessor) : base(stronglyTypedKeyValuePairAccessor)
{
}

private protected GeneratedBase(global::System.Collections.Generic.IDictionary dictionary) : base(dictionary)
{
}

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

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

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

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

private static string GetMemberName(global::System.Linq.Expressions.Expression> 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."),
};
}
}
```