5

I have created a TestComponent.razor

@typeparam TValue

@code {
    private TValue Type { get; set; }
    [Parameter] public string String { get; set; }
}

In the index.razor page I have the following:

@page "/"

<h1>Hello, world!</h1>

Welcome to your new app.

<SurveyPrompt Title="How is Blazor working for you?" />

<ComponentFactory.Data.SampleComponent TValue="@myType" String="@myString"></ComponentFactory.Data.SampleComponent>

@code{
    Type myType { get; set; } = typeof(string);
    string myString { get; set; } = "hello";
}

I cannot pass Type myType into TValue, unless I make myType a @typeparam of the current page

Why is this happening and is there a way to pass variables into a component's @typeparam?

1
  • It would probably be better to describe what you are trying to achieve, because of course you can pass a type to a component, by making a parameter that accepts a type, but we don't know what you want to do because you have decided how to do "it", found out that method doesn't work and just asked how to make that method work, which it won't. Explain what you want you component to be able to do and someone will be able to help Commented Dec 28, 2020 at 14:35

1 Answer 1

10

You cannot create Blazor components using a “variable” generic type argument. Just like with normal generic types in C#, these type arguments need to be known at compile time and as such you will have to specify your type directly when creating the component.

In your case, this could look like this:

<SampleComponent TValue="string" Type="some string" String="@myString" />

Since you have used your generic type argument TValue for the property Type, you can also leave out the TValue="string" explicitly and have the compiler complete that for you:

<SampleComponent Type="some string" String="@myString" />

If you want to create a component dynamically then what you can do is to dynamically create a RenderFragment that renders the component. That way

The only way to create a generic component with a dynamic type argument at run time would be to use reflection. You can create a RenderFragment to create a component dynamically:

<div>
   @SampleComponentInstance
</div>

@code{
    RenderFragment SampleComponentInstance => builder =>
    {
        var type = typeof(SampleComponent<>).MakeGenericType(new[] { MyType });
        builder.OpenComponent(1, type);
        builder.AddAttribute(2, "String", MyString);
        builder.CloseComponent();
    };

    Type MyType { get; set; } = typeof(string);
    string MyString { get; set; } = "hello";
}

This would render the SampleComponent with the generic type argument MyType inside the div.

Sign up to request clarification or add additional context in comments.

4 Comments

Hi, using reflection to create a generic component with a dynamic type is exactly what I would like to achieve. I have tried feeding TValue="@typeof(TItem).GetProperty(PropertyName).PropertyType" but it throws errors.
@Wlbjtsthy I have expanded my answer with an example on how to create a component dynamically.
Thanks! It works. But it only works when there is only one @typeparam. var type = typeof(SampleComponent<>).MakeGenericType(new[] { MyType, MySecondType }); returns an error saying that SampleComponent<> requires two params. Is there a way to make it work for multiple params?
Turns out that I need to do it this way: typeof(SampleComponent<,>).MakeGenericType(MyType, MySecondType);

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.