2. .NET components
.NET은 크게 아래 3가지 요소로 구성되어 있습니다.
컴파일러 | C#이나 F#, Visual Basic과 같은 언어로 된 소스코드를 IL(intermediate language)로 변환하는 것이며 C# 6.0 이후로 마이크로소프트는 Roslyn이라는 이름으로 컴파일러를 오픈소스화 하였습니다. |
CoreCLR(Common Language Runtime) | rumtime에 IL이 담긴 Assembly를 로드하여 IL코드를 해당 컴퓨터의 CPU에 맞는 네이티브 코드로 변환하고 스레드나 메모리와 같은 관리환경안에서 코드를 실행합니다. |
BCL or CoreFX(Base Class Libraries) | 사전에 빌드된 어셈블리의 모음이며 App을 개발할때 필요한 기능에 맞춰 여러가지 Library들을 사용할 수 있습니다. 대부분의 어셈블리는 App을 빌드할때 NuGet패키지 시스템을 통해 배포됩니다. |
● 어셈블리(Assemblie), NuGet
어셈블리는 Type이 파일로 저장된 것이며 Code를 배포하기 위한 메커니즘에 해당합니다. 대부분의 어셈블리는 DLL이나 EXE형식의 파일로 컴파일되어 만들어지는데 예를 들어 System.Data.dll은 하나의 어셈블리이며 이 어셈블리는 Data를 관리하기 위한 Type을 포함하고 있습니다. Type을 사용하기 위해서는 해당 어셈블리를 참조해야 하며 어셈블리는 이미 만들어진 형태의 정적 형태가 될 수 있고 Runtime에서 만들어지는 동적 형태가 될 수 있습니다.
NuGet Package 시스템은 이러한 어셈블리들을 온라인상에서 다운로드하여 필요한 어셈블리를 프로젝트에 사용할 수 있는 것으로서 하나의 NuGet Package는 필요에 따라서 다수의 어셈블리나 다른 리소스를 포함하고 있을 수 있습니다. 마이크로소프트의 NuGet Package Feed는 여기서 찾을 수 있습니다.
.NET자체로는 하나의 큰 단위이지만 이것을 세부적으로 나누어 작은 Package로 분리하여 배포하게 되었고 그것을 NuGet을 통해 내려받아 사용할 수 있는데 이렇게 나누어진 어셈블리는 동일한 이름의 Package이름으로 배포되고 있습니다.
NuGet을 통해서는 Package가 쉽게 배포할 수 있고 Package를 내려받을 때 다른 의존적인 Package로 같이 배포됨으로써 의존성 문제도 해결할 수 있습니다.
● 네임스페이스(Namespace)
네임스페이스는 Type의 주소이며 Type의 짧은 이름보다는 네임스페이스와 Type명을 결합해 Type을 식별하는 용도로 사용합니다. 예를 들어 System.Web.Mvc에 속해있는 IActionFilter인터페이스는 이름은 같지만 System.Web.Http.Filters에 속해있는 IActionFilter인터페이스와는 다른 것입니다.
App에서 필요로 하는 대부분의 일반적인 타입은 System.Runtime.dll안에 있습니다. 그렇지 않은 경우도 있지만 네임스페이스와 어셈블리파일이름은 항상 1:1로 연결되지 않습니다. 하나의 어셈블리 안에는 많은 네임스페이스들이 존재할 수 있고 반대로 하나의 네임스페이스는 다수의 어셈블리에서 존재할 수 있습니다.
예를 들어 System.Runtime.dll안에는 System, System.Collections, System.Collections.Generic등의 네임스페이스가 존재하는데 이들 네임스페이스를 통해서 Int32, String, IEnumerable<T>와 같은 Type이 사용되는 것입니다.
따라서 아래와 같이 XDocument Type을 사용하고자 하는 경우
XDocument xd = new();
우선 해당 Type을 정의하고 있는 System.Xml.Linq를 참조하고 아래와 같이 using을 통해 XDocument의 네임스페이스를 지정해야 합니다.
using System.Xml.Linq;
namespace myapp
{
class Program
{
static void Main(string[] args)
{
XDocument xd = new();
}
}
}
● 의존성(dependency)
만약 A라는 어셈블리가 존재한다고 했을때 B라는 어셈블리에서 A어셈블리를 참조해 어떤 기능이 구현되었다면 B라는 어셈블리는 단독적으로 실행될 수 없는 상태가 되고 이때 B는 A에 '의존'한다라고 할 수 있습니다. 어셈블리가 EXE형식의 실행파일 형태로 컴파일되었다 하더라도 다른 어셈블리를 참조해서 사용하고 있다면 그 역시 해당 참조하고 있는 어셈블리 없이는 실행이 불가능합니다.
단, 어셈블리는 상호간에 의존성이 성립될 수는 없습니다. 예를 들어 A어셈블리가 B라는 어셈블리를 참조하면서 다시 B가 A어셈블리를 참조할 수 없는 것입니다. 드물긴 하지만 이런 경우가 발생한다면 인터페이스를 통해 문제를 해결해야 합니다.
● Framework
Package는 App개발에 필요한 API를 정의하고 있고 Framework는 이러한 Package의 그룹에 해당합니다. 반대로 Package 없는 Framework는 어떠한 API도 정의할 수 없습니다.
.NET Package는 자신이 지원하는 Framework가 설정되어 있는데 예를 들어 4.3.0버전의 System.IO.FileSystem은 아래 Framework를 지원하므로
.NET Standard 1.3 버전이상 |
.NET Framework 4.6 버전 이상 |
Six Mono와 Xamarin platforms |
Package를 사용할때 현재 프로젝트의 Framework가 어떤 것인지를 알고 지원되는 패키지만을 사용해야 합니다.
● Keyword와 .NET type
C#에서는 문자열값을 다루기 위해 아래와 같이 해줄 수 있습니다.
string s1 = "abc";
String s2 = "abc";
위 2개의 s1과 s2변수는 정확하게 "abc"값을 담게 됩니다. 그렇다면 위에서 사용한 string과 String의 차이는 뭘까? 소문자 s가 사용되었다는 것과 대문자 S가 사용되었다는 것 외에 사실상 아무런 차이가 없습니다.
string이나 int와 같은 Keyword는 class library assembly안에 있는 .NET Type의 별칭이며 String이나 Int32는 별칭이 아닌 Type명 자체를 그대로 사용했다는 것일 뿐 기능적으로는 완전히 동일한 것입니다. string을 사용했다면 컴파일러는 이것을 System.String으로 인식하고 int를 사용했다면 컴파일러는 System.Int32으로 인식하고 처리합니다.
참고로 System.String으로 하지 않고 String만으로도 가능한데 이는 System네임스페이스가 기본적으로(Gloabl Namespace임) 이미 선언되어 있기 때문입니다. 만약 이러한 네임스페이스의 선언을 제거해야 한다면 프로젝트 파일(csproj)에 아래와 같은 요소를 추가하여 원하는 네임스페이스 선언을 제거할 수 있습니다.
<ItemGroup>
<Using Remove="System" />
</ItemGroup>
반면 string과 같은 keyword는 네임스페이스의 선언을 필요로 하지 않습니다.
.NET에는 위와 같은 원리로 사용되는 여러 Type관련 Keyword가 존재하는데
keyword | Type | keyword | Type |
string | System.String | char | System.Char |
sbyte | System.SByte | byte | System.Byte |
short | System.Int16 | ushort | System.UInt16 |
int | System.Int32 | uint | System.UInt32 |
long | System.Int64 | ulong | System.UInt64 |
nint | System.IntPtr | nuint | System.UIntPtr |
float | System.Single | double | System.Double |
decimal | System.Decimal | bool | System.Boolean |
object | System.Object | dynamic | System.Dynamic.DynamicObject |
C#외에도 .NET언어라면 같은 방식의 keyword를 사용할 수 있습니다. 예를 들어 Visual Basic.NET의 경우에는 System.Int32 대신 keyword인 Integer를 사용할 수 있습니다.
nint와 nuint는 C# 9에서 추가된 것으로 System.IntPtr과 System.UIntPtr Type으로 연결되어 있습니다. 이들 Type이 실제 가질 수 있는 크기의 범위는 현재 실행되는 Flatform에 따라 달라집니다. 예를 들어 32bit 시스템의 경우 4 byte의 크기를 가지게 되지만 64bit라면 8 byte의 크기를 가지게 됩니다.
● .NET Standard 사용
.NET Standard이전에는 PCLs(Portable Class Libraries)라는 것이 존재했는데 이를 통해서 명시적으로 Xamarin, Silverlight, Windows 8처럼 지원되는 Platform의 Code를 작성할 수 있었습니다. 하지만 마이크로소프트는 PCLs방식이 문제가 있음을 깨닫고 모든 Platform을 지원할 수 있는 단일적인 API를 만들게 되는데 그것이 .NET Standard입니다.
.NET Standard 2.0에서는 당시 최신의 .NET Platform의 핵심을 모두 통합하였고 .NET Core 3.0과 Xamarin에 대한 지원이 추가된 .NET Standard 2.1까지 발표되었습니다.
.NET Standard는 HTML5와 비슷한데 구글의 크롬이나 마이크로소프트의 엣지가 HTML5를 구현하고 실행하는 것처럼 .NET Core, .NET Framework, Xamarin등이 .NET Standard를 구현하고 실행하는 것입니다. 따라서 레거시 .NET이나 기타 다른 Platform에서 작동하는 Code를 작성해야 한다면 .NET Standard에 맞춰 Code를 구현하기만 하면 되는 것입니다. 특히 .NET Standard 2.1에서는 몇몇 API가 추가되었는데 이 때문에 runtime에 대한 변화가 요구되었습니다. .NET Framework 4.8은 레거시에 해당되는 Platform으로서 가능한한 runtime의 변화가 적용되지 않아야 했기에 .NET Standard 2.0까지만을 지원하게 되었습니다. 따라서 .NET Framework를 지원해야 하는 레거시 App에서는 .NET Standard 2.0까지만을 지원하도록 해야 합니다.
어떤 버전의 .NET Standard를 선택할지는 지원하고자 하는 Platform과 기능 사이에 균형을 잘 따져야 합니다. 더욱더 낮은 수준의 많은 Platform을 지원하고자 한다면 그 만큼 사용 가능한 API가 줄어들겠지만 높은 버전의 몇몇 최신 Platform만을 지원하려고 하면 그만큼 많은 API를 적용할 수 있게 됩니다.
● .NET SDK
사용하고자 하는 .NET SDK의 버전에 따라 지원되는 .NET의 버전은 달라질 수 있습니다. 예를 들어 .NET Core 3.1의 경우 .NET Standard 2.0이 기본으로 적용되며 .NET SDK 5.0과 .NET SDK 6.0은 각각 .NET 5와 .NET6가 적용됩니다. 다만 이러한 적용 방식은 기본적인 것일 뿐 Project에서는 타깃이 되는 .NET의 버전을 상위 호환성으로 바꾸는 것은 얼마든지 가능한 일입니다.
.NET Standard 2.0 | .NET Framework 4.6.1 또는 그 이상 .NET Core 2.0 또는 그 이상 .NET 5.0 또는 그 이상 Mono 5.4 또는 그 이상 Xamarin.Android 8.0 또는 그 이상 Xamarin.iOS 10.14 또는 그 이상 |
.NET Standard 2.1 | .NET Core 3.0 또는 그 이상 .NET 5.0 또는 그 이상 Mono 6.4 또는 그 이상 Xamarin.Android 10.0 또는 그 이상 Xamarin.iOS 12.16 또는 그 이상 |
.NET 5.0 | .NET 5.0 또는 그 이상 |
.NET 6.0 | .NET 6.0 또는 그 이상 |
위의 표는 SDK에 따라 변경가능한 .NET의 Runtime 버전을 나타낸 것입니다.
● .NET Standard 2.0 사용하기
이미 언급한 것 처럼 .NET Standard 2.0을 사용해 만들어진 App은 레거시 .NET Framework는 물론 Windows, MacOS, Linux에서의 .NET 크로스 플랫폼에서도 사용될 수 있고 .NET의 다양한 API에도 접근할 수 있습니다.
.NET Standard 2.0을 사용하는 프로젝트를 생성하려면 아래와 같이 명령을 내려줄 수 있습니다.
dotnet new classlib -f netstandard2.0
|
● 기본 .NET SDK 변경하기
일반적으로 프로젝트는 가장 최신의 SDK를 사용하는 것을 기본으로 생성되지만 임의로 사용되는 SDK의 버전을 조정할 수 있습니다.
우선 아래 명령을 통해 현재 시스템에 설치된 .NET SDK의 버전을 확인해 봅니다.
dotnet --list-sdks |
5.0.202 [C:\Program Files\dotnet\sdk]
5.0.408 [C:\Program Files\dotnet\sdk] 6.0.101 [C:\Program Files\dotnet\sdk] 6.0.201 [C:\Program Files\dotnet\sdk] 6.0.300 [C:\Program Files\dotnet\sdk] |
예제에서는 현재 설치된 SDK중 가장 낮은 버전으로 5.0.202가 설치되어 있는 것을 알 수 있습니다.
만약 기본으로 사용될 SDK의 버전이 5.0.202가 사용되길 원한다면 아래 명령을 통해 global.json파일을 생성하도록 합니다.
dotnet new globaljson --sdk-version 5.0.202
|
이 파일은 dotnet명령이 실행될때 현재 폴더나 혹은 상위 폴더를 확인하여 global.json파일이 존재하는 경우 해당 파일안에 지정된 버전의 SDK를 사용하도록 하는데 실제 global.json파일을 열어보면 아래와 같은 내용이 존재함을 볼 수 있습니다.
{
"sdk": {
"version": "5.0.202"
}
}
이제 임의로 프로젝트를 하나 생성한뒤
dotnet new classlib
|
해당 프로젝트의 csproj파일을 열어 TargetFramework의 버전을 확인해 봅니다.
<Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup>
<TargetFramework>net5.0</TargetFramework>
</PropertyGroup>
</Project>
'.NET' 카테고리의 다른 글
[.NET] 닷넷 - 4. Decompiling (0) | 2022.06.24 |
---|---|
[.NET] 닷넷 - 3. 배포하기 (0) | 2022.06.24 |
[.NET] 닷넷 - 1. .NET 6 개요 (0) | 2022.06.24 |
[ASP.NET Core] IIS 배포 (게시) (0) | 2021.12.15 |
[Visual Studio IDE] Visual Studio IDE의 Registry 설정 (0) | 2021.11.27 |