Skip to content

Commit 25cd7ae

Browse files
committed
Add support for CSharpHelper for List literals
Fixes #19274 Also relates to npgsql/efcore.pg#2402
1 parent 27a83b9 commit 25cd7ae

File tree

2 files changed

+110
-0
lines changed

2 files changed

+110
-0
lines changed

src/EFCore.Design/Design/Internal/CSharpHelper.cs

Lines changed: 91 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -737,6 +737,73 @@ public virtual string Literal(object?[,] values)
737737
return builder.ToString();
738738
}
739739

740+
/// <summary>
741+
/// This is an internal API that supports the Entity Framework Core infrastructure and not subject to
742+
/// the same compatibility standards as public APIs. It may be changed or removed without notice in
743+
/// any release. You should only use it directly in your code with extreme caution and knowing that
744+
/// doing so can result in application failures when updating to a new Entity Framework Core release.
745+
/// </summary>
746+
public virtual string Literal<T>(IList<T> values, bool vertical = false)
747+
=> List(typeof(T), values, vertical);
748+
749+
private string List(Type type, IEnumerable values, bool vertical = false)
750+
{
751+
var builder = new IndentedStringBuilder();
752+
753+
builder.Append("new List<")
754+
.Append(Reference(type))
755+
.Append("> {");
756+
757+
if (vertical)
758+
{
759+
builder.AppendLine();
760+
builder.IncrementIndent();
761+
}
762+
else
763+
{
764+
builder.Append(" ");
765+
}
766+
767+
var first = true;
768+
foreach (var value in values)
769+
{
770+
if (first)
771+
{
772+
first = false;
773+
}
774+
else
775+
{
776+
builder.Append(",");
777+
778+
if (vertical)
779+
{
780+
builder.AppendLine();
781+
}
782+
else
783+
{
784+
builder.Append(" ");
785+
}
786+
}
787+
788+
builder.Append(UnknownLiteral(value));
789+
}
790+
791+
if (vertical)
792+
{
793+
builder.AppendLine();
794+
builder.DecrementIndent();
795+
}
796+
else
797+
{
798+
builder.Append(" ");
799+
}
800+
801+
builder.Append("}");
802+
803+
804+
return builder.ToString();
805+
}
806+
740807
/// <summary>
741808
/// This is an internal API that supports the Entity Framework Core infrastructure and not subject to
742809
/// the same compatibility standards as public APIs. It may be changed or removed without notice in
@@ -844,6 +911,11 @@ public virtual string UnknownLiteral(object? value)
844911
return Array(literalType.GetElementType()!, array);
845912
}
846913

914+
if (value is IList list && value.GetType().IsGenericType && value.GetType().GetGenericTypeDefinition() == typeof(List<>))
915+
{
916+
return List(value.GetType().GetGenericArguments()[0], list);
917+
}
918+
847919
var mapping = _typeMappingSource.FindMapping(literalType);
848920
if (mapping != null)
849921
{
@@ -878,6 +950,25 @@ private bool HandleExpression(Expression expression, StringBuilder builder, bool
878950

879951
HandleList(((NewArrayExpression)expression).Expressions, builder, simple: true);
880952

953+
builder
954+
.Append(" }");
955+
956+
return true;
957+
case ExpressionType.ListInit:
958+
if (((ListInitExpression)expression).Initializers.Any(_ => _.Arguments.Count != 1))
959+
{
960+
// if there is one more than one element in the arguments we can't make a literal cleanly
961+
return false;
962+
}
963+
964+
builder
965+
.Append("new ")
966+
.Append(Reference(expression.Type))
967+
.Append(" { ");
968+
969+
HandleList(((ListInitExpression)expression)
970+
.Initializers.Select(_ => _.Arguments.First()), builder, simple: true);
971+
881972
builder
882973
.Append(" }");
883974

test/EFCore.Design.Tests/Design/Internal/CSharpHelperTest.cs

Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -121,6 +121,12 @@ public void Literal_works_when_many_ByteArray()
121121
new byte[] { 1, 2 },
122122
"new byte[] { 1, 2 }");
123123

124+
[ConditionalFact]
125+
public void Literal_works_when_string_list()
126+
=> Literal_works(
127+
new List<string> { "one", "two" },
128+
@"new List<string> { ""one"", ""two"" }");
129+
124130
[ConditionalFact]
125131
public void Literal_works_when_multiline_string()
126132
=> Literal_works(
@@ -607,6 +613,19 @@ public void Literal_with_add()
607613
new CSharpHelper(typeMapping).UnknownLiteral(new SimpleTestType()));
608614
}
609615

616+
[ConditionalFact]
617+
public void Literal_with_list_of_string_init()
618+
{
619+
var typeMapping = CreateTypeMappingSource<SimpleTestType>(
620+
v => Expression.ListInit(
621+
Expression.New(typeof(List<>).MakeGenericType(typeof(string))),
622+
Expression.Constant("one"), Expression.Constant("two")));
623+
624+
Assert.Equal(
625+
@"new List<string> { ""one"", ""two"" }",
626+
new CSharpHelper(typeMapping).UnknownLiteral(new SimpleTestType()));
627+
}
628+
610629
[ConditionalFact]
611630
public void Literal_with_unsupported_node_throws()
612631
{

0 commit comments

Comments
 (0)