Skip to content

Commit

Permalink
Add support for CSharpHelper for Dictionary literals
Browse files Browse the repository at this point in the history
  • Loading branch information
yinzara committed Jun 29, 2022
1 parent f72888f commit e314e5b
Show file tree
Hide file tree
Showing 2 changed files with 92 additions and 7 deletions.
61 changes: 57 additions & 4 deletions src/EFCore.Design/Design/Internal/CSharpHelper.cs
Original file line number Diff line number Diff line change
Expand Up @@ -754,12 +754,57 @@ private string List(Type type, IEnumerable values, bool vertical = false)
.Append(Reference(type))
.Append(">");

return HandleEnumerable(builder, vertical, values, value =>
{
builder.Append(UnknownLiteral(value));
});
}

/// <summary>
/// This is an internal API that supports the Entity Framework Core infrastructure and not subject to
/// the same compatibility standards as public APIs. It may be changed or removed without notice in
/// any release. You should only use it directly in your code with extreme caution and knowing that
/// doing so can result in application failures when updating to a new Entity Framework Core release.
/// </summary>
public virtual string Literal<TKey, TValue>(Dictionary<TKey, TValue> dict, bool vertical = false)
where TKey : notnull
=> Dictionary(typeof(TKey), typeof(TValue), dict, vertical);

private string Dictionary(Type keyType, Type valueType, IDictionary dict, bool vertical = false)
{
var builder = new IndentedStringBuilder();

builder.Append("new Dictionary<")
.Append(Reference(keyType))
.Append(",")
.Append(Reference(valueType))
.Append(">");

return HandleEnumerable(builder, vertical, dict.Keys, key =>
{
builder.Append("[")
.Append(UnknownLiteral(key))
.Append("] = ")
.Append(UnknownLiteral(dict[key]));
});
}

private static string HandleEnumerable(IndentedStringBuilder builder, bool vertical, IEnumerable values, Action<object> handleValue)
{
var first = true;
foreach (var value in values)
{
if (first)
{
builder.Append(" {");
if (vertical)
{
builder.AppendLine();
}
else
{
builder.Append(" ");
}
builder.Append("{");
if (vertical)
{
builder.AppendLine();
Expand All @@ -785,7 +830,7 @@ private string List(Type type, IEnumerable values, bool vertical = false)
}
}

builder.Append(UnknownLiteral(value));
handleValue(value);
}

if (first)
Expand Down Expand Up @@ -917,9 +962,17 @@ public virtual string UnknownLiteral(object? value)
return Array(literalType.GetElementType()!, array);
}

if (value is IList list && value.GetType().IsGenericType && value.GetType().GetGenericTypeDefinition() == typeof(List<>))
var valueType = value.GetType();
if (valueType.IsGenericType && !valueType.IsGenericTypeDefinition)
{
return List(value.GetType().GetGenericArguments()[0], list);
var genericArguments = valueType.GetGenericArguments();
switch (value)
{
case IList list when genericArguments.Length == 1 && valueType.GetGenericTypeDefinition() == typeof(List<>):
return List(genericArguments[0], list);
case IDictionary dict when genericArguments.Length == 2 && valueType.GetGenericTypeDefinition() == typeof(Dictionary<,>):
return Dictionary(genericArguments[0], genericArguments[1], dict);
}
}

var mapping = _typeMappingSource.FindMapping(literalType);
Expand Down
38 changes: 35 additions & 3 deletions test/EFCore.Design.Tests/Design/Internal/CSharpHelperTest.cs
Original file line number Diff line number Diff line change
Expand Up @@ -140,10 +140,42 @@ public void Literal_works_when_list_of_mixed_objects()
@"new List<object> { 1, ""two"" }");

[ConditionalFact]
public void Literal_works_when_list_with_ctor_arguments()
public void Literal_works_when_list_vertical()
=> Assert.Equal(
@"new List<object>
{
1,
""two""
}".ReplaceLineEndings(), new CSharpHelper(TypeMappingSource).Literal(
new List<object> { 1, "two" }, true));

[ConditionalFact]
public void Literal_works_when_empty_dictionary()
=> Literal_works(
new Dictionary<string,int>(),
@"new Dictionary<string,int>()");

[ConditionalFact]
public void Literal_works_when_dictionary_with_single_element()
=> Literal_works(
new List<string>(new [] { "one" }) { "two", "three" },
@"new List<string> { ""one"", ""two"", ""three"" }");
new Dictionary<string,string> { ["one"] = "value" },
@"new Dictionary<string,string> { [""one""] = ""value"" }");

[ConditionalFact]
public void Literal_works_when_dictionary_of_mixed_objects()
=> Literal_works(
new Dictionary<string,object> { ["one"] = 1, ["two"] = "Two" },
@"new Dictionary<string,object> { [""one""] = 1, [""two""] = ""Two"" }");

[ConditionalFact]
public void Literal_works_when_dictionary_vertical()
=> Assert.Equal(
@"new Dictionary<int,object>
{
[1] = 1,
[2] = ""Two""
}".ReplaceLineEndings(), new CSharpHelper(TypeMappingSource).Literal(
new Dictionary<int,object> { [1] = 1, [2] = "Two" }, true));

[ConditionalFact]
public void Literal_works_when_multiline_string()
Expand Down

0 comments on commit e314e5b

Please sign in to comment.