플랫폼 간 대상 지정

최신 .NET은 여러 운영 체제와 디바이스를 지원합니다. .NET 오픈 소스 라이브러리는 Azure에 호스트되는 ASP.NET 웹 사이트를 빌드하든, Unity에서 .NET 게임을 빌드하든 간에, 가능한 한 많은 개발자를 지원하는 것이 중요합니다.

.NET 및 .NET Standard 대상

.NET 및 .NET Standard 대상은 .NET 라이브러리에 플랫폼 간 지원을 추가하는 가장 좋은 방법입니다.

  • .NET Standard는 모든 .NET 구현에서 사용할 수 있는 .NET API 사양입니다. .NET Standard를 대상으로 지정하면, 지정된 .NET Standard 버전에 있는 API를 사용하도록 제한된 라이브러리를 생성할 수 있습니다. 이 경우, 해당 버전의 .NET Standard를 구현하는 모든 플랫폼에서 라이브러리를 사용할 수 있습니다.
  • .NET 6-8은 .NET의 구현입니다. Windows 데스크톱 앱과 크로스 플랫폼 콘솔 앱, 클라우드 서비스, 웹 사이트에 사용할 수 있는 일관된 기능 및 API 집합을 갖춘 단일 제품입니다.

.NET이 .NET Standard와 비교되는 방법에 대한 자세한 내용은 .NET 5 및 .NET Standard를 참조하세요.

.NET Standard

프로젝트가 .NET 또는 .NET Standard를 대상으로 하고 성공적으로 컴파일되는 경우 라이브러리가 모든 플랫폼에서 성공적으로 실행되도록 보장하지는 않습니다.

  • 플랫폼 특정 API는 다른 플랫폼에서 실패합니다. 예를 들어 Microsoft.Win32.Registry은 Windows에서 성공하지만, 다른 OS에서 사용할 때는 PlatformNotSupportedException을 throw합니다.
  • API가 다르게 동작할 수 있습니다. 예를 들어 애플리케이션이 iOS 또는 UWP에서 Ahead-Of-Time 컴파일을 사용할 때 리플렉션 API는 서로 다른 성능 특성을 갖습니다.

.NET 팀은 가능한 문제를 검색하는 데 도움이 되는 플랫폼 호환성 분석기를 제공합니다.

✔️ netstandard2.0 대상을 포함하여 시작합니다.

대부분의 범용 라이브러리는 .NET Standard 2.0 외부의 API가 필요하지 않습니다. .NET Standard 2.0은 모든 최신 플랫폼에서 지원되며, 하나의 대상으로 여러 플랫폼을 지원하는 권장 방법입니다. .NET Framework를 지원할 필요가 없는 경우 .NET Standard 2.1을 대상으로 지정할 수도 있습니다.

✔️ 최신 .NET에 도입된 새 API가 필요한 경우 net6.0 대상 이상을 포함해야 합니다.

.NET 6 이상 앱은 netstandard2.0 대상을 사용할 수 있으므로 net6.0가 필요하지 않습니다. 명시적으로 net6.0, net7.0, net8.0을 대상으로 지정하거나 최신 .NET API를 사용하려는 경우를 지정해야 합니다.

netstandard1.x 대상을 포함하지 않습니다.

.NET Standard 1.x는 세분화된 NuGet 패키지 집합으로 배포되어 큰 패키지 종속성 그래프를 만들기 때문에 개발자가 빌드 시 많은 패키지를 다운로드해야 합니다. 최신 .NET 구현은 .NET Standard 2.0을 지원합니다. 특별히 이전 플랫폼을 대상으로 지정해야 하는 경우에만 .NET Standard 1.x를 대상으로 지정해야 합니다.

✔️ netstandard1.x 대상이 필요한 경우 netstandard2.0 대상을 포함합니다.

이전 플랫폼도 계속 작동하고 netstandard1.x 대상을 사용하도록 대체되는 동시에, .NET Standard 2.0을 지원하는 모든 플랫폼은 netstandard2.0 대상을 사용하고 더 작은 패키지 그래프의 혜택을 얻게 됩니다.

❌ 라이브러리가 플랫폼 특정 앱 모델을 사용하는 경우 .NET Standard 대상을 포함하지 마세요.

예를 들어 UWP 제어 도구 키트 라이브러리는 UWP에서만 사용할 수 있는 앱 모델에 종속됩니다. 앱 모델 특정 API는 .NET Standard에서 사용할 수 없습니다.

멀티 타기팅

라이브러리에서 프레임워크 특정 API에 액세스해야 하는 경우도 있습니다. 프레임워크 특정 API를 호출하는 가장 좋은 방법은 단일 프레임워크가 아니라 많은 .NET 대상 프레임워크 용으로 사용자 프로젝트를 빌드하는 다중 대상 지정을 사용하는 것입니다.

소비자가 개별 프레임워크용으로 빌드할 필요가 없도록 보호하려면 .NET Standard 출력과 하나 이상의 프레임워크 특정 출력을 사용해야 합니다. 다중 대상 지정을 사용하면 모든 어셈블리가 단일 NuGet 패키지 안에 패키지됩니다. 그러면 소비자가 동일한 패키지를 참조할 수 있으며, NuGet이 적절한 구현을 선택합니다. NuGet 패키지가 프레임워크 특정 구현을 제공하는 경우를 제외하고, 사용자 .NET Standard 라이브러리는 모든 곳에서 사용되는 대체 라이브러리 역할을 합니다. 멀티 타기팅을 통해 코드에서 조건부 컴파일을 사용하고 프레임워크 특정 API를 호출할 수 있습니다.

NuGet package with multiple assemblies

✔️ .NET Standard 외에도 .NET 구현을 대상으로 지정하는 것을 고려하세요.

.NET 구현을 대상으로 지정하면 .NET Standard 외부에 있는 플랫폼 특정 API를 호출할 수 있습니다.

이때 .NET Standard에 대한 지원을 삭제하지 마세요. 대신, 구현에서 throw하고 기능 API를 제공합니다. 이렇게 하면 사용자 라이브러리를 어느 곳에서나 사용할 수 있으며 런타임 기능 강화가 지원됩니다.

public static class GpsLocation
{
    // This project uses multi-targeting to expose device-specific APIs to .NET Standard.
    public static async Task<(double latitude, double longitude)> GetCoordinatesAsync()
    {
#if NET462
        return CallDotNetFrameworkApi();
#elif WINDOWS_UWP
        return CallUwpApi();
#else
        throw new PlatformNotSupportedException();
#endif
    }

    // Allows callers to check without having to catch PlatformNotSupportedException
    // or replicating the OS check.
    public static bool IsSupported
    {
        get
        {
#if NET462 || WINDOWS_UWP
            return true;
#else
            return false;
#endif
        }
    }
}

✔️ 프로젝트에 라이브러리 또는 패키지 종속성이 있는 경우 소스 코드가 모든 대상에 대해 동일한 경우에도 다중 대상 지정을 고려합니다.

프로젝트의 종속 패키지(직접 또는 다운스트림)는 대상 프레임워크당 다른 버전의 종속 어셈블리 내에 래핑되는 동안 동일한 코드 API를 사용할 수 있습니다. 특정 대상을 추가하면 소비자가 어셈블리 바인딩 리디렉션을 추가하거나 업데이트할 필요가 없습니다.

❌ 소스 코드가 모든 대상에 대해 동일하고 프로젝트에 라이브러리 또는 패키지 종속성이 없는 경우 .NET Standard를 대상으로 지정할 뿐만 아니라 다중 대상 지정을 피합니다.

NuGet에서 자동으로 .NET Standard 어셈블리를 사용합니다. 개별 .NET 구현을 대상으로 지정하면 아무 혜택 없이 *.nupkg 크기만 증가합니다.

✔️ netstandard2.0 대상을 제공할 때 net462의 대상을 추가하는 것을 고려하세요.

.NET Framework의 .NET Standard 2.0을 사용하는 경우 .NET Framework 4.7.2에서 해결된 몇 가지 문제가 발생합니다. .NET Framework 4.6.2용으로 빌드된 이진을 제공하면 여전히 .NET Framework 4.6.2 - 4.7.1을 사용 중인 개발자의 경험을 개선할 수 있습니다.

✔️ 수행 NuGet 패키지를 사용하여 라이브러리를 배포합니다.

NuGet은 개발자에게 가장 적합한 대상을 선택하여 적절한 구현을 선택할 필요가 없도록 보호합니다.

✔️ 멀티 타기팅 시 프로젝트 파일의 TargetFrameworks 속성을 사용합니다.

<Project Sdk="Microsoft.NET.Sdk">
  <PropertyGroup>
    <!-- This project will output netstandard2.0 and net462 assemblies -->
    <TargetFrameworks>netstandard2.0;net462</TargetFrameworks>
  </PropertyGroup>
</Project>

✔️ UWP 및 Xamarin에 대한 멀티 타기팅 시 MSBuild.Sdk.Extras를 사용합니다. 그러면 프로젝트 파일이 훨씬 간소화됩니다.

❌ 어셈블리 이름을 변경하거나 라이브러리가 컴파일하는 각 TFM에 대해 다른 어셈블리 이름을 사용하지 마세요. 라이브러리 간의 종속성으로 인해 TFM당 어셈블리 이름이 다른 다중 대상 지정은 패키지 소비자를 중단할 수 있습니다. 어셈블리는 모든 TFM에서 이름이 같아야 합니다.

이전 대상

.NET은 더 이상 일반적으로 사용되지 않는 플랫폼뿐만 아니라 오래전에 지원이 중단된 .NET Framework 버전을 대상으로 지정할 수 있도록 지원합니다. 가능한 한 많은 대상에서 라이브러리가 작동하도록 하는 것은 중요하지만, 누락된 API를 해결하기 위해 상당한 오버헤드가 추가될 수 있습니다. 특정 프레임워크는 도달률 및 제한 사항을 고려할 때 더 이상 대상으로 지정할 가치가 없습니다.

❌ PCL(이식 가능한 클래스 라이브러리) 대상을 포함하지 마세요. 예들 들어 portable-net45+win8+wpa81+wp8입니다.

.NET Standard는 플랫폼 간 .NET 라이브러리를 지원하는 최신 방법으로, PCL을 대체합니다.

❌ 더 이상 지원되지 않는 .NET 플랫폼의 대상을 포함하지 마세요. 예: SL4, WP