Skip to content

Commit cfc5aff

Browse files
authored
Support generic array parameters for components (#34734)
PR Title Using generic arrays as component parameters resulted in compilation failures which are now fixed. PR Description Before it was only possible to have generic parameters like IList<T> / Func<T> but not T[] / IList<T[]> / Func<T[]> because a different check for arrays is required. Fixes #34711
1 parent b3deb36 commit cfc5aff

File tree

15 files changed

+715
-1
lines changed

15 files changed

+715
-1
lines changed

src/Razor/Microsoft.AspNetCore.Razor.Language/test/IntegrationTests/ComponentCodeGenerationTestBase.cs

Lines changed: 59 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -231,6 +231,65 @@ @typeparam TItem2
231231
CompileToAssembly(generated);
232232
}
233233

234+
[Fact]
235+
public void ComponentWithTypeParameterArray()
236+
{
237+
// Arrange
238+
var classes = @"
239+
public class Tag
240+
{
241+
public string description { get; set; }
242+
}
243+
";
244+
245+
AdditionalSyntaxTrees.Add(Parse(classes));
246+
247+
// Act
248+
var generated = CompileToCSharp(@"
249+
@using Microsoft.AspNetCore.Components;
250+
@typeparam TItem
251+
252+
<h1>Item</h1>
253+
254+
<p>@ChildContent(Items1)</p>
255+
256+
@foreach (var item in Items2)
257+
{
258+
<p>@ChildContent(item)</p>
259+
}
260+
261+
<p>@ChildContent(Items3())</p>
262+
263+
@code {
264+
[Parameter] public TItem[] Items1 { get; set; }
265+
[Parameter] public List<TItem[]> Items2 { get; set; }
266+
[Parameter] public Func<TItem[]> Items3 { get; set; }
267+
[Parameter] public RenderFragment<TItem[]> ChildContent { get; set; }
268+
}");
269+
270+
// Assert
271+
AssertDocumentNodeMatchesBaseline(generated.CodeDocument);
272+
AssertCSharpDocumentMatchesBaseline(generated.CodeDocument);
273+
CompileToAssembly(generated);
274+
275+
AdditionalSyntaxTrees.Add(Parse(generated.CodeDocument.GetCSharpDocument().GeneratedCode));
276+
var useGenerated = CompileToCSharp("UseTestComponent.cshtml", @"
277+
@using Test
278+
<TestComponent Items1=items1 Items2=items2 Items3=items3>
279+
<p>@context[0].description</p>
280+
</TestComponent>
281+
282+
@code {
283+
static Tag tag = new Tag() { description = ""A description.""};
284+
Tag[] items1 = new [] { tag };
285+
List<Tag[]> items2 = new List<Tag[]>() { new [] { tag } };
286+
Tag[] items3() => new [] { tag };
287+
}");
288+
AssertDocumentNodeMatchesBaseline(useGenerated.CodeDocument);
289+
AssertCSharpDocumentMatchesBaseline(useGenerated.CodeDocument);
290+
CompileToAssembly(useGenerated);
291+
}
292+
234293
[Fact]
235294
public void ComponentWithConstrainedTypeParameters()
236295
{
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,92 @@
1+
// <auto-generated/>
2+
#pragma warning disable 1591
3+
namespace Test
4+
{
5+
#line hidden
6+
using System;
7+
using System.Collections.Generic;
8+
using System.Linq;
9+
using System.Threading.Tasks;
10+
#nullable restore
11+
#line 1 "x:\dir\subdir\Test\TestComponent.cshtml"
12+
using Microsoft.AspNetCore.Components;
13+
14+
#line default
15+
#line hidden
16+
#nullable disable
17+
public partial class TestComponent<TItem> : Microsoft.AspNetCore.Components.ComponentBase
18+
{
19+
#pragma warning disable 219
20+
private void __RazorDirectiveTokenHelpers__() {
21+
((System.Action)(() => {
22+
#nullable restore
23+
#line 2 "x:\dir\subdir\Test\TestComponent.cshtml"
24+
global::System.Object TItem = null!;
25+
26+
#line default
27+
#line hidden
28+
#nullable disable
29+
}
30+
))();
31+
}
32+
#pragma warning restore 219
33+
#pragma warning disable 0414
34+
private static System.Object __o = null;
35+
#pragma warning restore 0414
36+
#pragma warning disable 1998
37+
protected override void BuildRenderTree(Microsoft.AspNetCore.Components.Rendering.RenderTreeBuilder __builder)
38+
{
39+
#nullable restore
40+
#line 6 "x:\dir\subdir\Test\TestComponent.cshtml"
41+
__o = ChildContent(Items1);
42+
43+
#line default
44+
#line hidden
45+
#nullable disable
46+
#nullable restore
47+
#line 8 "x:\dir\subdir\Test\TestComponent.cshtml"
48+
foreach (var item in Items2)
49+
{
50+
51+
52+
#line default
53+
#line hidden
54+
#nullable disable
55+
#nullable restore
56+
#line 10 "x:\dir\subdir\Test\TestComponent.cshtml"
57+
__o = ChildContent(item);
58+
59+
#line default
60+
#line hidden
61+
#nullable disable
62+
#nullable restore
63+
#line 10 "x:\dir\subdir\Test\TestComponent.cshtml"
64+
65+
}
66+
67+
#line default
68+
#line hidden
69+
#nullable disable
70+
#nullable restore
71+
#line 13 "x:\dir\subdir\Test\TestComponent.cshtml"
72+
__o = ChildContent(Items3());
73+
74+
#line default
75+
#line hidden
76+
#nullable disable
77+
}
78+
#pragma warning restore 1998
79+
#nullable restore
80+
#line 15 "x:\dir\subdir\Test\TestComponent.cshtml"
81+
82+
[Parameter] public TItem[] Items1 { get; set; }
83+
[Parameter] public List<TItem[]> Items2 { get; set; }
84+
[Parameter] public Func<TItem[]> Items3 { get; set; }
85+
[Parameter] public RenderFragment<TItem[]> ChildContent { get; set; }
86+
87+
#line default
88+
#line hidden
89+
#nullable disable
90+
}
91+
}
92+
#pragma warning restore 1591
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,47 @@
1+
Document -
2+
NamespaceDeclaration - - Test
3+
UsingDirective - (3:1,1 [12] ) - System
4+
UsingDirective - (18:2,1 [32] ) - System.Collections.Generic
5+
UsingDirective - (53:3,1 [17] ) - System.Linq
6+
UsingDirective - (73:4,1 [28] ) - System.Threading.Tasks
7+
UsingDirective - (1:0,1 [38] x:\dir\subdir\Test\TestComponent.cshtml) - Microsoft.AspNetCore.Components
8+
ClassDeclaration - - public partial - TestComponent - Microsoft.AspNetCore.Components.ComponentBase - - TItem
9+
DesignTimeDirective -
10+
DirectiveToken - (52:1,11 [5] x:\dir\subdir\Test\TestComponent.cshtml) - TItem
11+
CSharpCode -
12+
IntermediateToken - - CSharp - #pragma warning disable 0414
13+
CSharpCode -
14+
IntermediateToken - - CSharp - private static System.Object __o = null;
15+
CSharpCode -
16+
IntermediateToken - - CSharp - #pragma warning restore 0414
17+
MethodDeclaration - - protected override - void - BuildRenderTree
18+
HtmlContent - (39:0,39 [2] x:\dir\subdir\Test\TestComponent.cshtml)
19+
LazyIntermediateToken - (39:0,39 [2] x:\dir\subdir\Test\TestComponent.cshtml) - Html - \n
20+
HtmlContent - (59:2,0 [2] x:\dir\subdir\Test\TestComponent.cshtml)
21+
LazyIntermediateToken - (59:2,0 [2] x:\dir\subdir\Test\TestComponent.cshtml) - Html - \n
22+
MarkupElement - (61:3,0 [13] x:\dir\subdir\Test\TestComponent.cshtml) - h1
23+
HtmlContent - (65:3,4 [4] x:\dir\subdir\Test\TestComponent.cshtml)
24+
LazyIntermediateToken - (65:3,4 [4] x:\dir\subdir\Test\TestComponent.cshtml) - Html - Item
25+
HtmlContent - (74:3,13 [4] x:\dir\subdir\Test\TestComponent.cshtml)
26+
LazyIntermediateToken - (74:3,13 [4] x:\dir\subdir\Test\TestComponent.cshtml) - Html - \n\n
27+
MarkupElement - (78:5,0 [28] x:\dir\subdir\Test\TestComponent.cshtml) - p
28+
CSharpExpression - (82:5,4 [20] x:\dir\subdir\Test\TestComponent.cshtml)
29+
LazyIntermediateToken - (82:5,4 [20] x:\dir\subdir\Test\TestComponent.cshtml) - CSharp - ChildContent(Items1)
30+
HtmlContent - (106:5,28 [4] x:\dir\subdir\Test\TestComponent.cshtml)
31+
LazyIntermediateToken - (106:5,28 [4] x:\dir\subdir\Test\TestComponent.cshtml) - Html - \n\n
32+
CSharpCode - (111:7,1 [37] x:\dir\subdir\Test\TestComponent.cshtml)
33+
LazyIntermediateToken - (111:7,1 [37] x:\dir\subdir\Test\TestComponent.cshtml) - CSharp - foreach (var item in Items2)\n{\n
34+
MarkupElement - (148:9,4 [26] x:\dir\subdir\Test\TestComponent.cshtml) - p
35+
CSharpExpression - (152:9,8 [18] x:\dir\subdir\Test\TestComponent.cshtml)
36+
LazyIntermediateToken - (152:9,8 [18] x:\dir\subdir\Test\TestComponent.cshtml) - CSharp - ChildContent(item)
37+
CSharpCode - (174:9,30 [3] x:\dir\subdir\Test\TestComponent.cshtml)
38+
LazyIntermediateToken - (174:9,30 [3] x:\dir\subdir\Test\TestComponent.cshtml) - CSharp - \n}
39+
HtmlContent - (177:10,1 [4] x:\dir\subdir\Test\TestComponent.cshtml)
40+
LazyIntermediateToken - (177:10,1 [4] x:\dir\subdir\Test\TestComponent.cshtml) - Html - \n\n
41+
MarkupElement - (181:12,0 [30] x:\dir\subdir\Test\TestComponent.cshtml) - p
42+
CSharpExpression - (185:12,4 [22] x:\dir\subdir\Test\TestComponent.cshtml)
43+
LazyIntermediateToken - (185:12,4 [22] x:\dir\subdir\Test\TestComponent.cshtml) - CSharp - ChildContent(Items3())
44+
HtmlContent - (211:12,30 [4] x:\dir\subdir\Test\TestComponent.cshtml)
45+
LazyIntermediateToken - (211:12,30 [4] x:\dir\subdir\Test\TestComponent.cshtml) - Html - \n\n
46+
CSharpCode - (222:14,7 [248] x:\dir\subdir\Test\TestComponent.cshtml)
47+
LazyIntermediateToken - (222:14,7 [248] x:\dir\subdir\Test\TestComponent.cshtml) - CSharp - \n [Parameter] public TItem[] Items1 { get; set; }\n [Parameter] public List<TItem[]> Items2 { get; set; }\n [Parameter] public Func<TItem[]> Items3 { get; set; }\n [Parameter] public RenderFragment<TItem[]> ChildContent { get; set; }\n
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,56 @@
1+
Source Location: (1:0,1 [38] x:\dir\subdir\Test\TestComponent.cshtml)
2+
|using Microsoft.AspNetCore.Components;|
3+
Generated Location: (276:11,0 [38] )
4+
|using Microsoft.AspNetCore.Components;|
5+
6+
Source Location: (52:1,11 [5] x:\dir\subdir\Test\TestComponent.cshtml)
7+
|TItem|
8+
Generated Location: (688:23,22 [5] )
9+
|TItem|
10+
11+
Source Location: (82:5,4 [20] x:\dir\subdir\Test\TestComponent.cshtml)
12+
|ChildContent(Items1)|
13+
Generated Location: (1199:40,6 [20] )
14+
|ChildContent(Items1)|
15+
16+
Source Location: (111:7,1 [37] x:\dir\subdir\Test\TestComponent.cshtml)
17+
|foreach (var item in Items2)
18+
{
19+
|
20+
Generated Location: (1343:47,1 [37] )
21+
|foreach (var item in Items2)
22+
{
23+
|
24+
25+
Source Location: (152:9,8 [18] x:\dir\subdir\Test\TestComponent.cshtml)
26+
|ChildContent(item)|
27+
Generated Location: (1511:56,8 [18] )
28+
|ChildContent(item)|
29+
30+
Source Location: (174:9,30 [3] x:\dir\subdir\Test\TestComponent.cshtml)
31+
|
32+
}|
33+
Generated Location: (1683:63,30 [3] )
34+
|
35+
}|
36+
37+
Source Location: (185:12,4 [22] x:\dir\subdir\Test\TestComponent.cshtml)
38+
|ChildContent(Items3())|
39+
Generated Location: (1815:71,6 [22] )
40+
|ChildContent(Items3())|
41+
42+
Source Location: (222:14,7 [248] x:\dir\subdir\Test\TestComponent.cshtml)
43+
|
44+
[Parameter] public TItem[] Items1 { get; set; }
45+
[Parameter] public List<TItem[]> Items2 { get; set; }
46+
[Parameter] public Func<TItem[]> Items3 { get; set; }
47+
[Parameter] public RenderFragment<TItem[]> ChildContent { get; set; }
48+
|
49+
Generated Location: (2017:80,7 [248] )
50+
|
51+
[Parameter] public TItem[] Items1 { get; set; }
52+
[Parameter] public List<TItem[]> Items2 { get; set; }
53+
[Parameter] public Func<TItem[]> Items3 { get; set; }
54+
[Parameter] public RenderFragment<TItem[]> ChildContent { get; set; }
55+
|
56+
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,102 @@
1+
// <auto-generated/>
2+
#pragma warning disable 1591
3+
namespace Test
4+
{
5+
#line hidden
6+
using System;
7+
using System.Collections.Generic;
8+
using System.Linq;
9+
using System.Threading.Tasks;
10+
using Microsoft.AspNetCore.Components;
11+
#nullable restore
12+
#line 1 "x:\dir\subdir\Test\UseTestComponent.cshtml"
13+
using Test;
14+
15+
#line default
16+
#line hidden
17+
#nullable disable
18+
public partial class UseTestComponent : Microsoft.AspNetCore.Components.ComponentBase
19+
{
20+
#pragma warning disable 219
21+
private void __RazorDirectiveTokenHelpers__() {
22+
}
23+
#pragma warning restore 219
24+
#pragma warning disable 0414
25+
private static System.Object __o = null;
26+
#pragma warning restore 0414
27+
#pragma warning disable 1998
28+
protected override void BuildRenderTree(Microsoft.AspNetCore.Components.Rendering.RenderTreeBuilder __builder)
29+
{
30+
__Blazor.Test.UseTestComponent.TypeInference.CreateTestComponent_0(__builder, -1, -1,
31+
#nullable restore
32+
#line 2 "x:\dir\subdir\Test\UseTestComponent.cshtml"
33+
items1
34+
35+
#line default
36+
#line hidden
37+
#nullable disable
38+
, -1,
39+
#nullable restore
40+
#line 2 "x:\dir\subdir\Test\UseTestComponent.cshtml"
41+
items2
42+
43+
#line default
44+
#line hidden
45+
#nullable disable
46+
, -1,
47+
#nullable restore
48+
#line 2 "x:\dir\subdir\Test\UseTestComponent.cshtml"
49+
items3
50+
51+
#line default
52+
#line hidden
53+
#nullable disable
54+
, -1, (context) => (__builder2) => {
55+
#nullable restore
56+
#line 3 "x:\dir\subdir\Test\UseTestComponent.cshtml"
57+
__o = context[0].description;
58+
59+
#line default
60+
#line hidden
61+
#nullable disable
62+
}
63+
);
64+
#nullable restore
65+
#line 2 "x:\dir\subdir\Test\UseTestComponent.cshtml"
66+
__o = typeof(TestComponent<>);
67+
68+
#line default
69+
#line hidden
70+
#nullable disable
71+
}
72+
#pragma warning restore 1998
73+
#nullable restore
74+
#line 6 "x:\dir\subdir\Test\UseTestComponent.cshtml"
75+
76+
static Tag tag = new Tag() { description = "A description."};
77+
Tag[] items1 = new [] { tag };
78+
List<Tag[]> items2 = new List<Tag[]>() { new [] { tag } };
79+
Tag[] items3() => new [] { tag };
80+
81+
#line default
82+
#line hidden
83+
#nullable disable
84+
}
85+
}
86+
namespace __Blazor.Test.UseTestComponent
87+
{
88+
#line hidden
89+
internal static class TypeInference
90+
{
91+
public static void CreateTestComponent_0<TItem>(global::Microsoft.AspNetCore.Components.Rendering.RenderTreeBuilder __builder, int seq, int __seq0, TItem[] __arg0, int __seq1, global::System.Collections.Generic.List<TItem[]> __arg1, int __seq2, global::System.Func<TItem[]> __arg2, int __seq3, global::Microsoft.AspNetCore.Components.RenderFragment<TItem[]> __arg3)
92+
{
93+
__builder.OpenComponent<global::Test.TestComponent<TItem>>(seq);
94+
__builder.AddAttribute(__seq0, "Items1", __arg0);
95+
__builder.AddAttribute(__seq1, "Items2", __arg1);
96+
__builder.AddAttribute(__seq2, "Items3", __arg2);
97+
__builder.AddAttribute(__seq3, "ChildContent", __arg3);
98+
__builder.CloseComponent();
99+
}
100+
}
101+
}
102+
#pragma warning restore 1591

0 commit comments

Comments
 (0)