ASP.NET Core Razor 元件泛型型別支援
注意
這不是這篇文章的最新版本。 如需目前版本,請參閱本文的 .NET 8 版本。
警告
不再支援此版本的 ASP.NET Core。 如需詳細資訊,請參閱 .NET 和 .NET Core 支援原則。 如需目前版本,請參閱本文的 .NET 8 版本。
本文說明 Razor 元件中的泛型型別支援。
如果您不熟悉泛型型別,請參閱 泛型型別和方法 (C# 指南),以取得閱讀本文之前使用泛型的一般指導。
本文中的範例程式碼僅適用於 Blazor範例應用程式中的最新 .NET 版本。
一般類型參數支援
@typeparam
指示詞會宣告所產生元件類別的一般類型參數:
@typeparam TItem
系統支援具有 where
類型條件約束的 C# 語法:
@typeparam TEntity where TEntity : IEntity
支援 RenderFragment 泛型型別,但暫不支援做為泛型型別的元件。 若要依型別轉譯元件,請考慮使用 DynamicComponent。 如需詳細資訊,請參閱動態轉譯 ASP.NET Core Razor 元件。
在下列範例中,ListItems1
元件泛型型別為 TExample
,這代表 ExampleList
集合的類型。
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; }
}
@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; }
}
下列元件會轉譯兩個 ListItems1
元件:
- 字串或整數資料會指派給每個元件的
ExampleList
參數。 - 針對每個元件的類型參數 (
TExample
),系統會設定符合所指派資料類型的string
或int
類型。
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" />
@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" />
如需詳細資訊,請參閱 ASP.NET Core 的 Razor 語法參考。 如需使用樣板化元件來設定一般類型的範例,請參閱 ASP.NET Core Blazor 樣板化元件。
串聯一般類型支援
上階元件可以使用 [CascadingTypeParameter]
屬性,依名稱將類型參數串聯至子系。 此屬性可讓一般類型推斷自動搭配使用指定的類型參數與具有同名類型參數的子系。
藉由將 @attribute [CascadingTypeParameter(...)]
新增至元件,符合下列條件的子系會自動使用指定的一般類型引數:
- 巢狀為相同
.razor
文件中的元件子內容。 - 也宣告完全同名的
@typeparam
。 - 未針對類型參數明確提供或隱含推斷另一個值。 如果有提供或推斷另一個值,則其優先順序高於串聯的一般類型。
收到串聯的類型參數時,元件會從具有同名[CascadingTypeParameter]
屬性的最接近上階取得參數值。 特定樹狀子目錄內的串聯一般類型參數會遭到覆寫。
系統只會依名稱來執行比對。 因此,建議您避免使用具有一般名稱的串聯一般類型參數,例如 T
或 TItem
。 如果開發人員選擇串聯類型參數,則隱含表示其名稱足夠獨特,而不會與不相關元件中的其他串聯類型參數相衝突。
您可以在下列任一方法中,使用上階 (父代) 元件將泛型型別串聯至子元件,接下來的兩個子區段會有相關示範:
- 明確設定串聯一般類型。
- 推斷串聯一般類型。
下列子區段會舉例說明使用下列 ListDisplay1
元件來進行上述方法的過程。 元件會接收和轉譯泛型型別為 TExample
的清單資料。 若要讓 ListDisplay1
的每個執行個體脫穎而出,其他元件參數會控制清單的色彩。
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; }
}
@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; }
}
以上階元件為基礎的明確一般類型
本節中的示範會明確地針對 TExample
來串聯類型。
注意
本章節會使用 串聯泛型型別支援 一節中的上述 ListDisplay1
元件。
下列 ListItems2
元件會接收資料,並將名為 TExample
的一般類型參數串聯至其子代元件。 在即將到來的父元件中,ListItems2
元件可用來顯示具有上述 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; }
}
@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; }
}
下列父元件會設定兩個指定 ListItems2
類型 (TExample
) 的 ListItems2
元件所具有的子內容 (RenderFragment),這些類型會串聯至子元件。 ListDisplay1
元件會使用範例中顯示的清單項目資料來進行轉譯。 字串資料會與第一個 ListItems2
元件搭配使用,整數資料則會與第二個 ListItems2
元件搭配使用。
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>
@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>
明確指定類型也可讓您使用串聯值和參數來提供資料給子元件,如下列示範所示。
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; }
}
@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; }
}
@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; }
}
在下列範例中串聯資料時,必須向 元件提供類型。
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 };
}
@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 };
}
串聯多個一般類型時,必須傳遞集合中所有一般類型的值。 在下列範例中,TItem
、TValue
和 TEdit
是 GridColumn
一般類型,但放置 GridColumn
的父元件未指定 TItem
類型:
<GridColumn TValue="string" TEdit="TextEdit" />
上述範例會產生編譯時期錯誤,指出 GridColumn
元件遺漏 TItem
類型參數。 有效的程式碼會指定所有類型:
<GridColumn TValue="string" TEdit="TextEdit" TItem="User" />
以上階元件為基礎的推斷一般類型
本節中的示範會根據推斷來對 TExample
串聯類型。
注意
本章節會使用 串聯泛型型別支援 一節中的 ListDisplay
元件。
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; }
}
@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; }
}
具有推斷串聯類型的下列 元件會提供不同的資料以供顯示。
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>
@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>
具有推斷串聯類型的下列 元件會提供相同的資料以供顯示。 下列範例會將資料直接指派給元件。
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 };
}
@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 };
}