Skip to content
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

Allow generic type constraints #8433

Closed
Tracked by #27883
rkone opened this issue Mar 12, 2019 · 30 comments · Fixed by #31800
Closed
Tracked by #27883

Allow generic type constraints #8433

rkone opened this issue Mar 12, 2019 · 30 comments · Fixed by #31800
Assignees
Labels
affected-few This issue impacts only small number of customers area-blazor Includes: Blazor, Razor Components Components Big Rock This issue tracks a big effort which can span multiple issues Done This issue has been fixed enhancement This issue represents an ask for new feature or an enhancement to an existing one severity-major This label is used by an internal tool
Milestone

Comments

@rkone
Copy link

rkone commented Mar 12, 2019

We should be able to add generic constraints to our typeparam. For example:
@typeparam TEntity where TEntity : IEntity

As of preview3 gives the error "Unexpected literal following the 'typeparam' directive".

@muratg muratg added the area-mvc Includes: MVC, Actions and Controllers, Localization, CORS, most templates label Mar 12, 2019
@stsrki
Copy link
Contributor

stsrki commented Mar 21, 2019

I also think this is a much needed feature.

Any comment on this?

@mkArtakMSFT mkArtakMSFT added area-blazor Includes: Blazor, Razor Components enhancement This issue represents an ask for new feature or an enhancement to an existing one labels Mar 25, 2019
@mkArtakMSFT mkArtakMSFT added this to the 3.0.0-preview6 milestone Mar 29, 2019
@mkArtakMSFT mkArtakMSFT removed area-mvc Includes: MVC, Actions and Controllers, Localization, CORS, most templates labels May 9, 2019
@prosser
Copy link

prosser commented May 23, 2019

Without this feature, developers will be creating a lot of boilerplate components to workaround C# 8.0 #nullable limitations.

for example, take this overly-simplified .razor:

@typeparam TEnum
@typeparam TContainer
@inherits EnumButtonsComponent<TEnum, TContainer>

@if (Visible)
{
    <div class="btn-group-toggle" data-toggle="buttons">
        @foreach (var option in Options)
        {
            <label class="btn btn-primary @(Equals(Value, option.Value) ? "active" : "")">
                <input type="radio" name="@Name" value="@option.Value" checked="@(Equals(Value, option.Value))" onchange="@(() => Value = option.Value)"/>
                @option.Description
            </label>
        }
    </div>
}

And the class it's inheriting from:

public class EnumButtonsComponent<TEnum, TContainer> : EnumPickerComponentBase<TEnum, TContainer>
        where TEnum : struct
{
}

public class EnumPickerComponentBase<TEnum, TContainer> : AutoLabeledControlBase<TContainer>
    where TEnum : struct
{
    private string? stringValue;

    // without the constraint (or adding #nullable disable), TEnum is indeterminate. You cannot
    // mark it TEnum?, because it could be a value type. Not marking it as nullable raises a warning
    // because it could be null.
    private TEnum value = default;
    // implementation...
}

The EnumPickerComponentBase class needs the constraint due to #nullable limitations (have to pick either nullable or not nullable). Without this feature in Blazor, you would need to have a .razor for each type that you wanted an EnumPickerComponentBase-derived template.

@mkArtakMSFT mkArtakMSFT modified the milestones: 3.0.0-preview7, 3.1.0 May 24, 2019
@mkArtakMSFT mkArtakMSFT modified the milestones: 3.1.0, 5.0.0 Aug 12, 2019
@mkArtakMSFT mkArtakMSFT modified the milestones: 5.0.0, 5.0.0-preview1 Aug 19, 2019
@springy76
Copy link

If Razor Components would create partial classes (last time I checked this was planned for 3.1.0) then you could define these generics including constraints in your own partial c# class.

@smartprogrammer93
Copy link

Isn't this solved now with 3.1 preview 1??? partial classes are published

@springy76
Copy link

springy76 commented Oct 16, 2019

Isn't this solved now with 3.1 preview 1??? partial classes are published

Someone already tried this?

@stsrki
Copy link
Contributor

stsrki commented Oct 17, 2019

I have just tried it and it doesn't work for generic components at all. It works for basic partial class.

This works

public partial class CheckBox
{
    [Parameter] public RenderFragment ChildContent { get; set; }
}

Doesn't work

public partial class CheckBox<TValue>
    where TValue : struct
{
    [Parameter] public TValue Checked { get; set; }

    [Parameter] public EventCallback<TValue> CheckedChanged { get; set; }

    [Parameter] public RenderFragment ChildContent { get; set; }
}

@smartprogrammer93
Copy link

This is a very important feature in my opinion. I wish if it can be done by .Net Core 3.1

@SQL-MisterMagoo
Copy link
Contributor

@stsrki Can you explain what doesn't work?

If I add @typeparam TValue to a .razor file and add the same to the code behind partial class, with a constraint it works for me.

Razor file MyClass.razor
@typeparam TValue

Code behind MyClass.razor.cs

public partial class MyClass<TValue> where T:struct

Works as I would expect.

@stsrki
Copy link
Contributor

stsrki commented Oct 24, 2019

@SQL-MisterMagoo I was getting an error:

Error RZ9985 Multiple components use the tag 'CheckBox'. Components: BlazorApp10.Shared.CheckBox, BlazorApp10.Shared.CheckBox

You're right. If I add the @typeparam TValue to razor file the error is gone.

@rkone
Copy link
Author

rkone commented Oct 24, 2019

Thanks for the solution @SQL-MisterMagoo ! I didn't think about templates, as I just needed properties from the constraints for my control.

@miggat
Copy link

miggat commented Nov 18, 2019

I used @SQL-MisterMagoo suggestion, and i have:
Test.razor:
@typeparam TValue

Test.razor.cs
public partial class Test<TValue> where TValue: ISomeInterface

But i get this error on build:
Missing partial modifier on declaration of type 'Test'; another partial declaration of this type exists

Also, notice the generated Test.razor.g.cs constructor
public class Test<TValue> : Microsoft.AspNetCore.Components.ComponentBase

I'm probably doing something wrong since i just landed into Blazor, but i can't find the difference between your solution and mine

@FrancescoLorenzetti84
Copy link

I can confirm what @miggat said, I'm experiencing the same issue. This must be a bug.

@SQL-MisterMagoo
Copy link
Contributor

@miggat you need to be on 3.1 for the partial classes to work

@FrancescoLorenzetti84
Copy link

@SQL-MisterMagoo I am on 3.1.0-preview4.19579.2 and I have that error

@SQL-MisterMagoo
Copy link
Contributor

@miggat @FrancescoLorenzetti84 Here is a working sample for you

https://github.com/SQL-MisterMagoo/BlazorPartialConstraint

@ghost
Copy link

ghost commented Jul 23, 2020

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.

@mkArtakMSFT
Copy link
Member

We've moved this to Backlog as this is also possible to achieve using partial classes.

@joshlang
Copy link

Unless something changed since Feb 25, no, it's not.

@poke
Copy link
Contributor

poke commented Aug 2, 2020

@joshlang You may need to explicitly specify the type argument when you use your generic component. E.g.

<Fancy TItem="ItemType" Item="someItem"></Fancy>

@JayArrowz
Copy link

image
:(

@musictopia2
Copy link

Actually I found out I was able to achieve what was needed with partial classes. In that case, maybe no need for changes because a person should use partial classes anyways.

@poke
Copy link
Contributor

poke commented Aug 3, 2020

In that case, maybe no need for changes because a person should use partial classes anyways.

I wouldn't agree with that since there are plenty examples of components that require a generic constraint but do not really need a code-behind.

It's good that we can achieve what we need right now, so this isn't a pressing issue. The end goal however should be that we can do this without code-behind. I'm totally fine if that comes later with 6.0.

@ghost
Copy link

ghost commented Oct 9, 2020

Thanks for contacting us.
We're moving this issue to the Next sprint planning milestone for future evaluation / consideration. We will evaluate the request when we are planning the work for the next milestone. To learn more about what to expect next and how this issue will be handled you can read more about our triage process here.

@javiercn
Copy link
Member

This has been implemented in a4a3668 and will be available in 6.0 preview4.

@ghost ghost locked as resolved and limited conversation to collaborators May 16, 2021
Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.
Labels
affected-few This issue impacts only small number of customers area-blazor Includes: Blazor, Razor Components Components Big Rock This issue tracks a big effort which can span multiple issues Done This issue has been fixed enhancement This issue represents an ask for new feature or an enhancement to an existing one severity-major This label is used by an internal tool
Projects
None yet
Development

Successfully merging a pull request may close this issue.