ASP.NET Core Razor 구성 요소 제네릭 형식 지원

참고 항목

이 문서의 최신 버전은 아닙니다. 현재 릴리스는 이 문서의 .NET 8 버전을 참조 하세요.

Important

이 정보는 상업적으로 출시되기 전에 실질적으로 수정될 수 있는 시험판 제품과 관련이 있습니다. Microsoft는 여기에 제공된 정보에 대해 어떠한 명시적, 또는 묵시적인 보증을 하지 않습니다.

현재 릴리스는 이 문서의 .NET 8 버전을 참조 하세요.

이 문서에서는 구성 요소의 Razor 제네릭 형식 지원에 대해 설명합니다.

제네릭 형식을 접하는 경우 이 문서를 읽기 전에 제네릭 사용에 대한 일반적인 지침은 제네릭 클래스 및 메서드(C# 가이드)를 참조하세요.

이 문서의 예제 코드는 샘플 앱의 최신 .NET 릴리스에 Blazor 만 사용할 수 있습니다.

제네릭 형식 매개 변수 지원

@typeparam 지시문은 생성된 구성 요소 클래스에 대한 제네릭 형식 매개 변수를 선언합니다.

@typeparam TItem

where 형식 제약 조건이 있는 C# 구문이 지원됩니다.

@typeparam TEntity where TEntity : IEntity

다음 예제 ListItems1 에서 구성 요소는 일반적으로 컬렉션의 ExampleList 형식을 나타내는 형식으로 TExample입력됩니다.

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; }
}

다음 구성 요소는 두 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" />

자세한 내용은 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; }
}

상위 구성 요소를 기반으로 하는 명시적 제네릭 형식

이 섹션의 데모에서는 TExample에 대해 형식을 명시적으로 연계합니다.

참고 항목

이 섹션에서는 Cascaded 제네릭 형식 지원 섹션의 이전 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; }
}

다음 부모 구성 요소는 자식 구성 요소에 연계되는 형식(RenderFragment)을 지정하는 ListItems2ListItems2 구성 요소의 자식 콘텐츠(TExample)를 설정합니다. 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>

형식을 명시적으로 지정하면 다음 데모에서 보여 주는 것과 같이 연계 값 및 매개 변수를 사용하여 자식 구성 요소에 데이터를 제공할 수도 있습니다.

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; }
}

다음 예에서 데이터를 연계할 때 구성 요소에 형식을 제공해야 합니다.

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 };
}

여러 제네릭 형식이 연계된 경우 집합의 모든 제네릭 형식에 대한 값을 전달해야 합니다. 다음 예에서 TItem, TValue, TEditGridColumn 제네릭 형식이지만, GridColumn을 배치하는 부모 구성 요소는 TItem 형식을 지정하지 않습니다.

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

앞의 예에서는 GridColumn 구성 요소에 TItem 형식 매개 변수가 누락되었다는 컴파일 시간 오류가 생성됩니다. 다음과 같이 유효한 코드는 모든 형식을 지정합니다.

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

상위 구성 요소를 기반으로 제네릭 형식 유추

이 섹션의 데모에서는 TExample에 대해 유추된 형식을 연계합니다.

참고 항목

이 섹션에서는 ListDisplay Cascaded 제네릭 형식 지원 섹션의 구성 요소를 사용합니다.

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; }
}

유추된 연계 형식이 있는 다음 구성 요소는 다른 데이터를 제공하여 표시합니다.

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>

유추된 연계 형식이 있는 다음 구성 요소는 동일한 데이터를 제공하여 표시합니다. 다음 예에서는 구성 요소에 데이터를 직접 할당합니다.

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 };
}