공용 언어 런타임의 형식 전달

형식 전달을 사용하면 원본 어셈블리를 사용하는 애플리케이션을 다시 컴파일하지 않고도 형식을 다른 어셈블리로 이동할 수 있습니다.

예를 들어 애플리케이션이 Utility.dll이라는 어셈블리에서 Example 클래스를 사용한다고 가정해 보세요. Utility.dll 개발자는 어셈블리를 리팩터링하고 이 과정에서 Example 클래스를 다른 어셈블리로 이동할 수 있습니다. 이전 버전의 Utility.dll이 새 버전의 Utility.dll과 관련 어셈블리로 바뀌는 경우 Example 클래스를 사용하는 애플리케이션은 새 버전의 Utility.dll에서 Example 클래스를 찾을 수 없기 때문에 실패합니다.

Utility.dll 개발자는 TypeForwardedToAttribute 특성을 사용하여 Example 클래스에 대한 요청을 전달하여 이를 방지할 수 있습니다. 새 버전의 Utility.dll에 이 특성이 적용된 경우 Example 클래스에 대한 요청은 현재 해당 클래스가 들어 있는 어셈블리로 전달됩니다. 기존 애플리케이션은 다시 컴파일하지 않고도 정상적으로 작동합니다.

형식 전달

다음 네 단계를 통해 형식을 전달할 수 있습니다.

  1. 형식의 소스 코드를 원본 어셈블리에서 대상 어셈블리로 이동합니다.

  2. 해당 형식이 있었던 어셈블리에서 이동된 형식에 대해 TypeForwardedToAttribute를 추가합니다. 다음 코드에서는 이동된 Example 형식의 특성을 보여 줍니다.

     [assembly:TypeForwardedToAttribute(Example::typeid)]
    
     [assembly:TypeForwardedToAttribute(typeof(Example))]
    
  3. 해당 형식이 현재 들어 있는 어셈블리를 컴파일합니다.

  4. 해당 형식이 있었던 어셈블리를 현재 해당 형식이 들어 있는 어셈블리에 대한 참조를 사용하여 다시 컴파일합니다. 예를 들어 명령줄에서 C# 파일을 컴파일할 경우 References(C# 컴파일러 옵션) 옵션을 사용하여 해당 형식이 들어 있는 어셈블리를 지정합니다. C++의 경우 소스 파일에서 #using 지시문을 사용하여 해당 형식이 들어 있는 어셈블리를 지정합니다.

C# 형식 전달 예제

위 가상의 예제 설명에서 계속해서 Utility.dll을 개발하고 있으며 Example 클래스가 있다고 상상해 보세요. Utility.csproj는 기본 클래스 라이브러리입니다.

<Project Sdk="Microsoft.NET.Sdk">

  <PropertyGroup>
    <TargetFramework>net6.0</TargetFramework>
    <Nullable>enable</Nullable>
    <ImplicitUsing>true</ImplicitUsing>
  </PropertyGroup>

</Project>

Example 클래스는 몇 가지 속성을 제공하고 Object.ToString을 재정의합니다.

using System;

namespace Common.Objects;

public class Example
{
    public string Message { get; init; } = "Hi friends!";

    public Guid Id { get; init; } = Guid.NewGuid();

    public DateOnly Date { get; init; } = DateOnly.FromDateTime(DateTime.Today);

    public sealed override string ToString() =>
        $"[{Id} - {Date}]: {Message}";
}

이제는 사용하는 프로젝트가 Consumer 어셈블리에 나타난다고 가정해 보겠습니다. 이 사용하는 프로젝트는 Utility 어셈블리를 참조합니다. 예를 들어 Example 개체를 인스턴스화하고 Program.cs 파일의 콘솔에 작성합니다.

using System;
using Common.Objects;

Example example = new();

Console.WriteLine(example);

사용하는 앱이 실행되면 Example 개체의 상태가 출력됩니다. 이 시점에서는 Consuming.csprojUtility.csproj를 참조하므로 형식 전달이 없습니다. 그러나 Utility 어셈블리 개발자는 리팩터링의 일부로 Example 개체를 제거하기로 결정합니다. 이 형식은 새로 만든 Common.csproj로 이동됩니다.

Utility 어셈블리에서 이 형식을 제거함으로써 개발자는 호환성이 손상되는 변경을 도입하고 있습니다. 사용하는 모든 프로젝트가 최신 Utility 어셈블리로 업데이트될 때는 사용이 중단됩니다.

사용하는 프로젝트에서 Common 어셈블리에 새 참조를 추가하도록 요구하는 대신 형식을 전달할 수 있습니다. Utility 어셈블리에서 이 형식이 제거되었으므로 Utility.csprojCommon.csproj를 참조하도록 해야 합니다.

<Project Sdk="Microsoft.NET.Sdk">

  <PropertyGroup>
    <TargetFramework>net6.0</TargetFramework>
    <Nullable>enable</Nullable>
    <ImplicitUsing>true</ImplicitUsing>
  </PropertyGroup>

  <ItemGroup>
    <ProjectReference Include="..\Common\Common.csproj" />
  </ItemGroup>

</Project>

이전 C# 프로젝트는 이제 새로 만든 Common 어셈블리를 참조합니다. 이는 PackageReference 또는 ProjectReference일 수 있습니다. Utility 어셈블리는 형식 전달 정보를 제공해야 합니다. 규칙에 따라 형식 전달 선언은 일반적으로 TypeForwarders라는 단일 파일에 캡슐화됩니다. Utility어셈블리에서 다음 TypeForwarders.cs C# 파일을 고려하세요.

using System.Runtime.CompilerServices;
using Common.Objects;

[assembly:TypeForwardedTo(typeof(Example))]

Utility 어셈블리는 Common 어셈블리를 참조하고 Example 형식을 전달합니다. 형식 전달 선언을 사용하여 Utility 어셈블리를 컴파일하고 Utility.dllConsuming 저장소에 놓으면 사용 중인 앱이 컴파일되지 않고 작동합니다.

참고 항목