-
Notifications
You must be signed in to change notification settings - Fork 10k
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Generic Blazor component can't correctly infer it's type when type has an additional constraint #25588
Comments
We've moved this issue to the Backlog milestone. This means that it is not going to be worked on for the coming release. We will reassess the backlog following the current release and consider this item at that time. To learn more about our issue management process and to have better expectation regarding different types of issues you can read our Triage Process. |
Just came across this myself. Would be a great improvement if it could be fixed. |
+1 for this! Thank you @MariovanZeist for the workaround! |
I think this is fixed in 6.0. @MariovanZeist can you check and if not, provide a minimal repro project? I did create the same components you did and things seem to be in order Here is my Index.razor <InferComponent Items="new MyClass[]{ new MyClass() }">
<NotInferComponent Items="new MyClass[] {}"></NotInferComponent>
</InferComponent>
<NotInferComponent Items="new MyClass[] {}">
<InferComponent Items="new MyClass[]{ new MyClass() }">
</InferComponent>
</NotInferComponent>
<NotInferComponent Items="new MyClass[] {}">
</NotInferComponent>
<InferComponent Items="new MyClass[]{ new MyClass() }">
</InferComponent> @typeparam T
<h3>InferComponent</h3>
@code {
[Parameter] public IEnumerable<T> Items { get; set; }
} @typeparam T where T : IMyInterface
<h3>NotInferComponent</h3>
@code {
[Parameter] public IEnumerable<T> Items { get; set; }
} #pragma checksum "C:\Users\jacalvar\source\repos\BlazorApp66\BlazorApp66\Pages\Index.razor" "{8829d00f-11b8-4213-878b-770e8597ac16}" "b4e4c7aae7395f7fe3f026556c35f26bd5351a366110865aa6c567572c48eb29"
// <auto-generated/>
#pragma warning disable 1591
namespace BlazorApp66.Pages
{
#line hidden
using System;
using System.Collections.Generic;
using System.Linq;
using System.Threading.Tasks;
using Microsoft.AspNetCore.Components;
#nullable restore
#line 1 "C:\Users\jacalvar\source\repos\BlazorApp66\BlazorApp66\_Imports.razor"
using System.Net.Http;
#line default
#line hidden
#nullable disable
#nullable restore
#line 2 "C:\Users\jacalvar\source\repos\BlazorApp66\BlazorApp66\_Imports.razor"
using Microsoft.AspNetCore.Authorization;
#line default
#line hidden
#nullable disable
#nullable restore
#line 3 "C:\Users\jacalvar\source\repos\BlazorApp66\BlazorApp66\_Imports.razor"
using Microsoft.AspNetCore.Components.Authorization;
#line default
#line hidden
#nullable disable
#nullable restore
#line 4 "C:\Users\jacalvar\source\repos\BlazorApp66\BlazorApp66\_Imports.razor"
using Microsoft.AspNetCore.Components.Forms;
#line default
#line hidden
#nullable disable
#nullable restore
#line 5 "C:\Users\jacalvar\source\repos\BlazorApp66\BlazorApp66\_Imports.razor"
using Microsoft.AspNetCore.Components.Routing;
#line default
#line hidden
#nullable disable
#nullable restore
#line 6 "C:\Users\jacalvar\source\repos\BlazorApp66\BlazorApp66\_Imports.razor"
using Microsoft.AspNetCore.Components.Web;
#line default
#line hidden
#nullable disable
#nullable restore
#line 7 "C:\Users\jacalvar\source\repos\BlazorApp66\BlazorApp66\_Imports.razor"
using Microsoft.AspNetCore.Components.Web.Virtualization;
#line default
#line hidden
#nullable disable
#nullable restore
#line 8 "C:\Users\jacalvar\source\repos\BlazorApp66\BlazorApp66\_Imports.razor"
using Microsoft.JSInterop;
#line default
#line hidden
#nullable disable
#nullable restore
#line 9 "C:\Users\jacalvar\source\repos\BlazorApp66\BlazorApp66\_Imports.razor"
using BlazorApp66;
#line default
#line hidden
#nullable disable
#nullable restore
#line 10 "C:\Users\jacalvar\source\repos\BlazorApp66\BlazorApp66\_Imports.razor"
using BlazorApp66.Shared;
#line default
#line hidden
#nullable disable
[Microsoft.AspNetCore.Components.RouteAttribute("/")]
public partial class Index : Microsoft.AspNetCore.Components.ComponentBase
{
#pragma warning disable 1998
protected override void BuildRenderTree(Microsoft.AspNetCore.Components.Rendering.RenderTreeBuilder __builder)
{
__builder.OpenComponent<Microsoft.AspNetCore.Components.Web.PageTitle>(0);
__builder.AddAttribute(1, "ChildContent", (Microsoft.AspNetCore.Components.RenderFragment)((__builder2) => {
__builder2.AddContent(2, "Index");
}
));
__builder.CloseComponent();
__builder.AddMarkupContent(3, "\r\n\r\n");
__builder.AddMarkupContent(4, "<h1>Hello, world!</h1>\r\n\r\nWelcome to your new app.\r\n\r\n");
__Blazor.BlazorApp66.Pages.Index.TypeInference.CreateInferComponent_0(__builder, 5, 6,
#nullable restore
#line 9 "C:\Users\jacalvar\source\repos\BlazorApp66\BlazorApp66\Pages\Index.razor"
new MyClass[]{ new MyClass() }
#line default
#line hidden
#nullable disable
, 7, (__builder2) => {
__Blazor.BlazorApp66.Pages.Index.TypeInference.CreateNotInferComponent_1(__builder2, 8, 9,
#nullable restore
#line 10 "C:\Users\jacalvar\source\repos\BlazorApp66\BlazorApp66\Pages\Index.razor"
new MyClass[] {}
#line default
#line hidden
#nullable disable
);
}
);
__builder.AddMarkupContent(10, "\r\n\r\n");
__Blazor.BlazorApp66.Pages.Index.TypeInference.CreateNotInferComponent_2(__builder, 11, 12,
#nullable restore
#line 13 "C:\Users\jacalvar\source\repos\BlazorApp66\BlazorApp66\Pages\Index.razor"
new MyClass[] {}
#line default
#line hidden
#nullable disable
, 13, (__builder2) => {
__Blazor.BlazorApp66.Pages.Index.TypeInference.CreateInferComponent_3(__builder2, 14, 15,
#nullable restore
#line 14 "C:\Users\jacalvar\source\repos\BlazorApp66\BlazorApp66\Pages\Index.razor"
new MyClass[]{ new MyClass() }
#line default
#line hidden
#nullable disable
);
}
);
__builder.AddMarkupContent(16, "\r\n\r\n");
__Blazor.BlazorApp66.Pages.Index.TypeInference.CreateNotInferComponent_4(__builder, 17, 18,
#nullable restore
#line 18 "C:\Users\jacalvar\source\repos\BlazorApp66\BlazorApp66\Pages\Index.razor"
new MyClass[] {}
#line default
#line hidden
#nullable disable
);
__builder.AddMarkupContent(19, "\r\n");
__Blazor.BlazorApp66.Pages.Index.TypeInference.CreateInferComponent_5(__builder, 20, 21,
#nullable restore
#line 20 "C:\Users\jacalvar\source\repos\BlazorApp66\BlazorApp66\Pages\Index.razor"
new MyClass[]{ new MyClass() }
#line default
#line hidden
#nullable disable
);
__builder.AddMarkupContent(22, "\r\n\r\n");
__builder.OpenComponent<BlazorApp66.Shared.SurveyPrompt>(23);
__builder.AddAttribute(24, "Title", "How is Blazor working for you?");
__builder.CloseComponent();
}
#pragma warning restore 1998
}
}
namespace __Blazor.BlazorApp66.Pages.Index
{
#line hidden
internal static class TypeInference
{
public static void CreateInferComponent_0<T>(global::Microsoft.AspNetCore.Components.Rendering.RenderTreeBuilder __builder, int seq, int __seq0, global::System.Collections.Generic.IEnumerable<T> __arg0, int __seq1, Microsoft.AspNetCore.Components.RenderFragment __arg1)
{
__builder.OpenComponent<global::BlazorApp66.Pages.InferComponent<T>>(seq);
__builder.AddAttribute(__seq0, "Items", __arg0);
__builder.AddAttribute(__seq1, "ChildContent", __arg1);
__builder.CloseComponent();
}
public static void CreateNotInferComponent_1<T>(global::Microsoft.AspNetCore.Components.Rendering.RenderTreeBuilder __builder, int seq, int __seq0, global::System.Collections.Generic.IEnumerable<T> __arg0)
where T : IMyInterface
{
__builder.OpenComponent<global::BlazorApp66.Pages.NotInferComponent<T>>(seq);
__builder.AddAttribute(__seq0, "Items", __arg0);
__builder.CloseComponent();
}
public static void CreateNotInferComponent_2<T>(global::Microsoft.AspNetCore.Components.Rendering.RenderTreeBuilder __builder, int seq, int __seq0, global::System.Collections.Generic.IEnumerable<T> __arg0, int __seq1, Microsoft.AspNetCore.Components.RenderFragment __arg1)
where T : IMyInterface
{
__builder.OpenComponent<global::BlazorApp66.Pages.NotInferComponent<T>>(seq);
__builder.AddAttribute(__seq0, "Items", __arg0);
__builder.AddAttribute(__seq1, "ChildContent", __arg1);
__builder.CloseComponent();
}
public static void CreateInferComponent_3<T>(global::Microsoft.AspNetCore.Components.Rendering.RenderTreeBuilder __builder, int seq, int __seq0, global::System.Collections.Generic.IEnumerable<T> __arg0)
{
__builder.OpenComponent<global::BlazorApp66.Pages.InferComponent<T>>(seq);
__builder.AddAttribute(__seq0, "Items", __arg0);
__builder.CloseComponent();
}
public static void CreateNotInferComponent_4<T>(global::Microsoft.AspNetCore.Components.Rendering.RenderTreeBuilder __builder, int seq, int __seq0, global::System.Collections.Generic.IEnumerable<T> __arg0)
where T : IMyInterface
{
__builder.OpenComponent<global::BlazorApp66.Pages.NotInferComponent<T>>(seq);
__builder.AddAttribute(__seq0, "Items", __arg0);
__builder.CloseComponent();
}
public static void CreateInferComponent_5<T>(global::Microsoft.AspNetCore.Components.Rendering.RenderTreeBuilder __builder, int seq, int __seq0, global::System.Collections.Generic.IEnumerable<T> __arg0)
{
__builder.OpenComponent<global::BlazorApp66.Pages.InferComponent<T>>(seq);
__builder.AddAttribute(__seq0, "Items", __arg0);
__builder.CloseComponent();
}
}
}
#pragma warning restore 1591 Let me know if you still find this issue (and please provide a repro for it) |
@javiercn It cannot find Below you find the generated source: (I added some comments) #pragma checksum "D:\My Projects\Reference Projects\BlazorConstraint\BlazorConstraint\Pages\Index.razor" "{8829d00f-11b8-4213-878b-770e8597ac16}" "54544ab82b3c41f78c37f12044b089c044acda30a0e2b79840203630c301649e"
// <auto-generated/>
#pragma warning disable 1591
namespace BlazorConstraint.Pages
{
#line hidden
using System;
using System.Collections.Generic;
using System.Linq;
using System.Threading.Tasks;
using Microsoft.AspNetCore.Components;
#nullable restore
#line 1 "D:\My Projects\Reference Projects\BlazorConstraint\BlazorConstraint\_Imports.razor"
using System.Net.Http;
#line default
#line hidden
#nullable disable
#nullable restore
#line 2 "D:\My Projects\Reference Projects\BlazorConstraint\BlazorConstraint\_Imports.razor"
using System.Net.Http.Json;
#line default
#line hidden
#nullable disable
#nullable restore
#line 3 "D:\My Projects\Reference Projects\BlazorConstraint\BlazorConstraint\_Imports.razor"
using Microsoft.AspNetCore.Components.Forms;
#line default
#line hidden
#nullable disable
#nullable restore
#line 4 "D:\My Projects\Reference Projects\BlazorConstraint\BlazorConstraint\_Imports.razor"
using Microsoft.AspNetCore.Components.Routing;
#line default
#line hidden
#nullable disable
#nullable restore
#line 5 "D:\My Projects\Reference Projects\BlazorConstraint\BlazorConstraint\_Imports.razor"
using Microsoft.AspNetCore.Components.Web;
#line default
#line hidden
#nullable disable
#nullable restore
#line 6 "D:\My Projects\Reference Projects\BlazorConstraint\BlazorConstraint\_Imports.razor"
using Microsoft.AspNetCore.Components.Web.Virtualization;
#line default
#line hidden
#nullable disable
#nullable restore
#line 7 "D:\My Projects\Reference Projects\BlazorConstraint\BlazorConstraint\_Imports.razor"
using Microsoft.AspNetCore.Components.WebAssembly.Http;
#line default
#line hidden
#nullable disable
#nullable restore
#line 8 "D:\My Projects\Reference Projects\BlazorConstraint\BlazorConstraint\_Imports.razor"
using Microsoft.JSInterop;
#line default
#line hidden
#nullable disable
#nullable restore
#line 9 "D:\My Projects\Reference Projects\BlazorConstraint\BlazorConstraint\_Imports.razor"
using BlazorConstraint;
#line default
#line hidden
#nullable disable
#nullable restore
#line 10 "D:\My Projects\Reference Projects\BlazorConstraint\BlazorConstraint\_Imports.razor"
using BlazorConstraint.Components;
#line default
#line hidden
#nullable disable
#nullable restore
#line 11 "D:\My Projects\Reference Projects\BlazorConstraint\BlazorConstraint\_Imports.razor"
using BlazorConstraint.Shared;
#line default
#line hidden
#nullable disable
[Microsoft.AspNetCore.Components.RouteAttribute("/")]
public partial class Index : Microsoft.AspNetCore.Components.ComponentBase
{
#pragma warning disable 1998
protected override void BuildRenderTree(Microsoft.AspNetCore.Components.Rendering.RenderTreeBuilder __builder)
{
__Blazor.BlazorConstraint.Pages.Index.TypeInference.CreateInferComponent_0(__builder, 0, 1,
#nullable restore
#line 3 "D:\My Projects\Reference Projects\BlazorConstraint\BlazorConstraint\Pages\Index.razor"
SimpleData.List
#line default
#line hidden
#nullable disable
);
__builder.AddMarkupContent(2, "\r\n");
__Blazor.BlazorConstraint.Pages.Index.TypeInference.CreateNonInferComponent_1(__builder, 3, 4,
#nullable restore
#line 4 "D:\My Projects\Reference Projects\BlazorConstraint\BlazorConstraint\Pages\Index.razor"
SimpleData.List
#line default
#line hidden
#nullable disable
);
}
#pragma warning restore 1998
}
}
//The below namespace is auto-generated, and no usings are included, so this might be the reason why it fails:
namespace __Blazor.BlazorConstraint.Pages.Index
{
#line hidden
internal static class TypeInference
{
public static void CreateInferComponent_0<T>(global::Microsoft.AspNetCore.Components.Rendering.RenderTreeBuilder __builder, int seq, int __seq0, global::System.Collections.Generic.IEnumerable<T> __arg0)
{
__builder.OpenComponent<global::BlazorConstraint.Components.InferComponent<T>>(seq);
__builder.AddAttribute(__seq0, "Items", __arg0);
__builder.CloseComponent();
}
public static void CreateNonInferComponent_1<T>(global::Microsoft.AspNetCore.Components.Rendering.RenderTreeBuilder __builder, int seq, int __seq0, global::System.Collections.Generic.IEnumerable<T> __arg0)
where T : IMyInterface //<- how should the compiler locate the Interface
//All other objects in this namespace are prefixed with their global namespace
{
__builder.OpenComponent<global::BlazorConstraint.Components.NonInferComponent<T>>(seq);
__builder.AddAttribute(__seq0, "Items", __arg0);
__builder.CloseComponent();
}
}
}
#pragma warning restore 1591 All the other referenced objects in the |
@MariovanZeist No problem, I was not able to repro and that makes it hard/impossible for me to determine what's goin on. I do see now this issue, and I think I'm reproing it (found the same issue by chance authoring another test). I believe the issue here is that we don't add the usings inside the type inference namespace and because of that, it's not able to find the types. |
It's either adding usings to the namespace or refering to objects using their global namespace notation. |
@javiercn There is another (tightly) related issue
But the following constraint is not: (a.k.a. Generic Constraints)
The generated sourcecode in both examples are public static void CreateNonInferComponent_1<T>(global::Microsoft.AspNetCore.Components.Rendering.RenderTreeBuilder __builder, int seq, int __seq0, global::System.Collections.Generic.IEnumerable<T> __arg0)
where T : IMyInterface Should I create a separate issue for this? |
@MariovanZeist thanks for pointing that out. I don't think we need an extra issue for that, I'll tackle it as part of the work we are currently doing |
@javiercn - This probably needs a new milestone |
@Pilchie good point. I updated it |
Fixed by dotnet/razor-compiler#44 (Including the generic type constraint in the type parameter described here) |
Is it possible if we'll see this fix in upcoming .NET 6 update? |
Describe the bug
When a generic Blazor component has a Generic Parameter with an additional constraint, it can't infer it's type correctly.
Example:
Define a basic class and interface
Say we have 2 components. (I will only show the code behind.)
And
And then use these 2 classes
InferComponent will correctly infer that it's
T
isMyClass
But NotInferComponent will report an error:
(The type 'T' cannot be used as type parameter 'T' in the generic type or method 'NotInferComponent'. There is no boxing conversion or type parameter conversion from 'T' to 'BlazorApp1.IMyInterface'. BlazorApp1)
The problem lies in the autogenerated razor.g.cs classes, and especially where it tries to get its type by type inference.
Below is part of the generated code. I added a remark with what is missing.
I think the solution would be that whenever the Blazor component that it wants to construct has additional constraints, these constraints should be added to the CreateComponentName function as well.
I don't think it's a duplicate of #8433, as the constraint on components itself works, it's the type inference that fails
Workaround
there is a workaround for this issue
add
T="MyClass"
as in
Will make it compile.
So we have a temporary solution for this issue, although I think it's confusing for the end-user to have to add
T="MyClass"
only when T has an additional constraint.To Reproduce
Repro: https://github.com/MariovanZeist/BlazorTypeinference
(based on Simple Blazor server app template)
Further technical details
Aspnetcore 5 preview 8
.NET SDK (reflecting any global.json):
Version: 5.0.100-preview.8.20417.9
Commit: fc62663a35
Runtime Environment:
OS Name: Windows
OS Version: 10.0.18363
OS Platform: Windows
RID: win10-x64
Base Path: C:\Program Files\dotnet\sdk\5.0.100-preview.8.20417.9\
Host (useful for support):
Version: 5.0.0-preview.8.20407.11
Commit: bf456654f9
.NET SDKs installed:
3.0.100 [C:\Program Files\dotnet\sdk]
3.1.201 [C:\Program Files\dotnet\sdk]
3.1.400-preview-015203 [C:\Program Files\dotnet\sdk]
3.1.401 [C:\Program Files\dotnet\sdk]
5.0.100-preview.8.20417.9 [C:\Program Files\dotnet\sdk]
.NET runtimes installed:
Microsoft.AspNetCore.All 2.1.2 [C:\Program Files\dotnet\shared\Microsoft.AspNetCore.All]
Microsoft.AspNetCore.All 2.1.4 [C:\Program Files\dotnet\shared\Microsoft.AspNetCore.All]
Microsoft.AspNetCore.All 2.1.21 [C:\Program Files\dotnet\shared\Microsoft.AspNetCore.All]
Microsoft.AspNetCore.App 2.1.2 [C:\Program Files\dotnet\shared\Microsoft.AspNetCore.App]
Microsoft.AspNetCore.App 2.1.4 [C:\Program Files\dotnet\shared\Microsoft.AspNetCore.App]
Microsoft.AspNetCore.App 2.1.21 [C:\Program Files\dotnet\shared\Microsoft.AspNetCore.App]
Microsoft.AspNetCore.App 3.0.0 [C:\Program Files\dotnet\shared\Microsoft.AspNetCore.App]
Microsoft.AspNetCore.App 3.1.3 [C:\Program Files\dotnet\shared\Microsoft.AspNetCore.App]
Microsoft.AspNetCore.App 3.1.7 [C:\Program Files\dotnet\shared\Microsoft.AspNetCore.App]
Microsoft.AspNetCore.App 5.0.0-preview.8.20414.8 [C:\Program Files\dotnet\shared\Microsoft.AspNetCore.App]
Microsoft.NETCore.App 2.1.21 [C:\Program Files\dotnet\shared\Microsoft.NETCore.App]
Microsoft.NETCore.App 3.0.0 [C:\Program Files\dotnet\shared\Microsoft.NETCore.App]
Microsoft.NETCore.App 3.1.3 [C:\Program Files\dotnet\shared\Microsoft.NETCore.App]
Microsoft.NETCore.App 3.1.7 [C:\Program Files\dotnet\shared\Microsoft.NETCore.App]
Microsoft.NETCore.App 5.0.0-preview.8.20407.11 [C:\Program Files\dotnet\shared\Microsoft.NETCore.App]
Microsoft.WindowsDesktop.App 3.0.0 [C:\Program Files\dotnet\shared\Microsoft.WindowsDesktop.App]
Microsoft.WindowsDesktop.App 3.1.3 [C:\Program Files\dotnet\shared\Microsoft.WindowsDesktop.App]
Microsoft.WindowsDesktop.App 3.1.7 [C:\Program Files\dotnet\shared\Microsoft.WindowsDesktop.App]
Microsoft.WindowsDesktop.App 5.0.0-preview.8.20411.6 [C:\Program Files\dotnet\shared\Microsoft.WindowsDesktop.App]
VS 2019 16.8 Preview 2.1
The text was updated successfully, but these errors were encountered: