podpora obecného typu komponenty ASP.NET Core Razor

Poznámka:

Toto není nejnovější verze tohoto článku. Aktuální verzi najdete ve verzi .NET 8 tohoto článku.

Důležité

Tyto informace se týkají předběžného vydání produktu, který může být podstatně změněn před komerčním vydáním. Microsoft neposkytuje žádné záruky, výslovné ani předpokládané, týkající se zde uváděných informací.

Aktuální verzi najdete ve verzi .NET 8 tohoto článku.

Tento článek popisuje podporu obecného typu v Razor součástech.

Pokud s obecnými typy teprve začínáte, přečtěte si téma Obecné třídy a metody (Průvodce jazykem C#), kde najdete obecné pokyny k použití obecných typů před přečtením tohoto článku.

Ukázkový kód v tomto článku je k dispozici pouze pro nejnovější verzi .NET v Blazor ukázkových aplikacích.

Podpora parametrů obecného typu

Direktiva @typeparam deklaruje pro generovanou třídu komponenty parametr obecného typu:

@typeparam TItem

Syntaxe jazyka C# s omezeními typu where se podporuje:

@typeparam TEntity where TEntity : IEntity

V následujícím příkladu ListItems1 je komponenta obecně zadána jako TExample, což představuje typ ExampleList kolekce.

ListItems1.razor:

@typeparam TExample

<h2>List Items 1</h2>

@if (ExampleList is not null)
{
    <ul style="color:@Color">
        @foreach (var item in ExampleList)
        {
            <li>@item</li>
        }
    </ul>

    <p>
        Type of <code>TExample</code>: @typeof(TExample)
    </p>
}

@code {
    [Parameter]
    public string? Color { get; set; }

    [Parameter]
    public IEnumerable<TExample>? ExampleList { get; set; }
}

Následující komponenta vykreslí dvě ListItems1 komponenty:

  • Parametru ExampleList každé komponenty se přiřadí řetězcová nebo celočíselná data.
  • Pro parametr typu (TExample) každé komponenty se nastaví typ string nebo int, který odpovídá typu přiřazených dat.

Generics1.razor:

@page "/generics-1"

<PageTitle>Generics 1</PageTitle>

<h1>Generic Type Example 1</h1>

<ListItems1 Color="blue"
            ExampleList="@(new List<string> { "Item 1", "Item 2" })"
            TExample="string" />

<ListItems1 Color="red"
            ExampleList="@(new List<int> { 1, 2 })"
            TExample="int" />

Další informace najdete v referenčních informacích k syntaxi Razor pro ASP.NET Core. Příklad nastavení obecného typu u komponent bez vizuálního vzhledu najdete v tématu Komponenty ASP.NET Core Blazor bez vizuálního vzhledu.

Podpora kaskádových obecných typů

Nadřazená komponenta může na potomky kaskádovat parametr typu podle názvu pomocí atributu [CascadingTypeParameter]. Tento atribut umožňuje při odvozování obecného typu automaticky použít zadaný parametr typu u potomků s parametrem typu se stejným názvem.

Po přidání atributu @attribute [CascadingTypeParameter(...)] do komponenty budou zadaný argument obecného typu automaticky používat potomci, kteří:

  • Jsou vnořeni jako podřízený obsah komponenty ve stejném dokumentu .razor.
  • Také deklarují direktivu @typeparam se stejným názvem.
  • Nemají pro parametr typu explicitně přiřazenou nebo implicitně odvozenou jinou hodnotu. Pokud se zadá nebo odvodí jiná hodnota, má přednost před kaskádovým obecným typem.

Při příjmu kaskádového parametru typu získají komponenty hodnotu parametru od nejbližšího nadřazeného objektu [CascadingTypeParameter] , který má atribut s odpovídajícím názvem. Kaskádové parametry obecného typu se přepisují v rámci konkrétního podstromu.

Porovnávání se provádí pouze podle názvu. Proto doporučujeme nepoužívat kaskádové parametry obecného typu s obecným názvem, například T nebo TItem. Pokud se vývojář rozhodne pro kaskádový parametr typu, implicitně se zavazuje zajistit, že jeho název bude dostatečně jedinečný na to, aby nekolidoval s dalšími kaskádovými parametry typu z nesouvisejících komponent.

Obecné typy lze kaskádově převést na podřízené komponenty s některým z následujících přístupů pro nadřazené (nadřazené) komponenty, které jsou demonstrovány v následujících dvou dílčích částech:

  • Explicitní nastavení kaskádového obecného typu
  • Odvození kaskádového obecného typu

Následující pododdíly poskytují příklady předchozích přístupů pomocí následující ListDisplay1 komponenty. Komponenta přijímá a vykresluje data seznamu obecně zadaných jako TExample. Aby každá instance vynikla, další parametr ListDisplay1 komponenty řídí barvu seznamu.

ListDisplay1.razor:

@typeparam TExample

@if (ExampleList is not null)
{
    <ul style="color:@Color">
        @foreach (var item in ExampleList)
        {
            <li>@item</li>
        }
    </ul>
}

@code {
    [Parameter]
    public string? Color { get; set; }

    [Parameter]
    public IEnumerable<TExample>? ExampleList { get; set; }
}

Explicitní obecné typy založené na nadřazených komponentách

Ukázka v této části explicitně kaskáduje typ TExample.

Poznámka:

Tato část používá předchozí ListDisplay1 komponentu v oddílu podpory kaskádového obecného typu.

Následující komponenta ListItems2 přijímá data a kaskáduje na své podřízené komponenty parametr obecného typu TExample. V další nadřazené komponentě se komponenta ListItems2 používá k zobrazení dat seznamu s předchozí komponentou ListDisplay1.

ListItems2.razor:

@attribute [CascadingTypeParameter(nameof(TExample))]
@typeparam TExample

<h2>List Items 2</h2>

@ChildContent

<p>
    Type of <code>TExample</code>: @typeof(TExample)
</p>

@code {
    [Parameter]
    public RenderFragment? ChildContent { get; set; }
}

Následující nadřazená komponenta nastaví podřízený obsah (RenderFragment) dvou ListItems2 komponent určujících ListItems2 typy (TExample), které jsou kaskádově na podřízené komponenty. Komponenty ListDisplay1 se vykreslí s použitím dat položek seznamu uvedených v příkladu. U první komponenty ListItems2 se použijí řetězcová data a u druhé komponenty ListItems2 se použijí celočíselná data.

Generics2.razor:

@page "/generics-2"

<PageTitle>Generics 2</PageTitle>

<h1>Generic Type Example 2</h1>

<ListItems2 TExample="string">
    <ListDisplay1 Color="blue" 
                  ExampleList="@(new List<string> { "Item 1", "Item 2" })" />
    <ListDisplay1 Color="red" 
                  ExampleList="@(new List<string> { "Item 3", "Item 4" })" />
</ListItems2>

<ListItems2 TExample="int">
    <ListDisplay1 Color="blue" 
                  ExampleList="@(new List<int> { 1, 2 })" />
    <ListDisplay1 Color="red" 
                  ExampleList="@(new List<int> { 3, 4 })" />
</ListItems2>

Explicitní zadání typu také umožňuje využít kaskádování hodnot a parametrů k poskytování dat podřízeným komponentám, jak ukazuje následující ukázka.

ListDisplay2.razor:

@typeparam TExample

@if (ExampleList is not null)
{
    <ul style="color:@Color">
        @foreach (var item in ExampleList)
        {
            <li>@item</li>
        }
    </ul>
}

@code {
    [Parameter]
    public string? Color { get; set; }

    [CascadingParameter]
    protected IEnumerable<TExample>? ExampleList { get; set; }
}

ListItems3.razor:

@attribute [CascadingTypeParameter(nameof(TExample))]
@typeparam TExample

<h2>List Items 3</h2>

@ChildContent

@if (ExampleList is not null)
{
    <ul style="color:green">
        @foreach (var item in ExampleList)
        {
            <li>@item</li>
        }
    </ul>

    <p>
        Type of <code>TExample</code>: @typeof(TExample)
    </p>
}

@code {
    [CascadingParameter]
    protected IEnumerable<TExample>? ExampleList { get; set; }

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

Při kaskádování dat v následujícím příkladu je potřeba zadat typ komponenty .

Generics3.razor:

@page "/generics-3"

<PageTitle>Generics 3</PageTitle>

<h1>Generic Type Example 3</h1>

<CascadingValue Value="stringData">
    <ListItems3 TExample="string">
        <ListDisplay2 Color="blue" />
        <ListDisplay2 Color="red" />
    </ListItems3>
</CascadingValue>

<CascadingValue Value="integerData">
    <ListItems3 TExample="int">
        <ListDisplay2 Color="blue" />
        <ListDisplay2 Color="red" />
    </ListItems3>
</CascadingValue>

@code {
    private List<string> stringData = new() { "Item 1", "Item 2" };
    private List<int> integerData = new() { 1, 2 };
}

V případě kaskádování několika obecných typů je nutné předat hodnoty všech obecných typů v sadě. V následujícím příkladu jsou parametry TItem, TValue a TEdit komponenty GridColumn obecného typu, ale v nadřazené komponentě, která generuje komponentu GridColumn, není zadaný typ TItem:

<GridColumn TValue="string" TEdit="TextEdit" />

Výše uvedený příklad způsobí chybu za kompilace, protože v komponentě GridColumn chybí parametr typu TItem. V platném kódu jsou zadané všechny typy:

<GridColumn TValue="string" TEdit="TextEdit" TItem="User" />

Odvozování obecných typů na základě nadřazených komponent

Ukázka v této části kaskáduje odvozený typ TExample.

Poznámka:

Tato část používá komponentu ListDisplay v oddílu podpory kaskádového obecného typu.

ListItems4.razor:

@attribute [CascadingTypeParameter(nameof(TExample))]
@typeparam TExample

<h2>List Items 4</h2>

@ChildContent

@if (ExampleList is not null)
{
    <ul style="color:green">
        @foreach (var item in ExampleList)
        {
            <li>@item</li>
        }
    </ul>

    <p>
        Type of <code>TExample</code>: @typeof(TExample)
    </p>
}

@code {
    [Parameter]
    public IEnumerable<TExample>? ExampleList { get; set; }

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

Následující komponenta s odvozenými kaskádovými typy poskytuje k zobrazení různá data.

Generics4.razor:

@page "/generics-4"

<PageTitle>Generics 4</PageTitle>

<h1>Generic Type Example 4</h1>

<ListItems4 ExampleList="@(new List<string> { "Item 5", "Item 6" })">
    <ListDisplay1 Color="blue" 
                  ExampleList="@(new List<string> { "Item 1", "Item 2" })" />
    <ListDisplay1 Color="red" 
                  ExampleList="@(new List<string> { "Item 3", "Item 4" })" />
</ListItems4>

<ListItems4 ExampleList="@(new List<int> { 5, 6 })">
    <ListDisplay1 Color="blue" 
                  ExampleList="@(new List<int> { 1, 2 })" />
    <ListDisplay1 Color="red" 
                  ExampleList="@(new List<int> { 3, 4 })" />
</ListItems4>

Následující komponenta s odvozenými kaskádovými typy poskytuje k zobrazení stejná data. Následující příklad přiřadí data přímo komponentám.

Generics5.razor:

@page "/generics-5"

<PageTitle>Generics 5</PageTitle>

<h1>Generic Type Example 5</h1>

<ListItems4 ExampleList="stringData">
    <ListDisplay1 Color="blue" ExampleList="stringData" />
    <ListDisplay1 Color="red" ExampleList="stringData" />
</ListItems4>

<ListItems4 ExampleList="integerData">
    <ListDisplay1 Color="blue" ExampleList="integerData" />
    <ListDisplay1 Color="red" ExampleList="integerData" />
</ListItems4>

@code {
    private List<string> stringData = new() { "Item 1", "Item 2" };
    private List<int> integerData = new() { 1, 2 };
}