Skip to content

Generic Blazor component can't correctly infer it's type when type has an additional constraint #25588

Closed
@MariovanZeist

Description

@MariovanZeist

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

    public class MyClass : IMyInterface
    {
    }

    public interface IMyInterface
    {
    }

Say we have 2 components. (I will only show the code behind.)

    partial class InferComponent<T>
    {
        [Parameter] public IEnumerable<T> Items { get; set; }
    }

And

    partial class NotInferComponent<T>
      where T : IMyInterface
    {
        [Parameter] public IEnumerable<T> Items { get; set; }
    }

And then use these 2 classes

<InferComponent Items="new MyClass[] { new MyClass() }"></InferComponent>

<NotInferComponent Items="new MyClass[] { new MyClass() }"></NotInferComponent>

InferComponent will correctly infer that it's T is MyClass

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.

namespace __Blazor.BlazorApp1.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::BlazorApp1.Components.InferComponent<T>>(seq);
        __builder.AddAttribute(__seq0, "Items", __arg0);
        __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    <--- This is missing
        {
        __builder.OpenComponent<global::BlazorApp1.Components.NotInferComponent<T>>(seq);
        __builder.AddAttribute(__seq0, "Items", __arg0);
        __builder.CloseComponent();
        }
    }
}

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

<NotInferComponent Items="new MyClass[] { new MyClass() }" T="MyClass"></NotInferComponent>

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

Metadata

Metadata

Assignees

Labels

Priority:1Work that is critical for the release, but we could probably ship withoutaffected-mostThis issue impacts most of the customersbugThis issue describes a behavior which is not expected - a bug.feature-razor.languageseverity-minorThis label is used by an internal tool

Type

No type

Projects

No projects

Milestone

Relationships

None yet

Development

No branches or pull requests

Issue actions