1. C#언어의 버전별 특징
● 1.0
객체지향 언어에 대한 모든 특징을 담고 2002년에 릴리즈 되었습니다.
● 2.0
2005년에 릴리즈 되었으며 generic을 통한 강력한 데이터 타입이 사용되기 시작했습니다. 이는 코드에 대한 성능의 증가와 함께 타입에러를 감소시키는 역활을 하였습니다. 또한 null 가능한 값형식이 추가되었습니다.
● 3.0
2007년에 릴리즈 되었으며 익명타입과 람다식 그리고 LINQ(Language INtegrated Queries)사용을 통한 서술적 코딩이 가능해 졌습니다. 또한 타입추론을 통한 암시적 지역변수 사용이 가능해졌습니다.
● 4.0
2010년에 릴리즈 되었으며 F#, Python과 같은 동적언어와의 상호운용성이 향상되었습니다. 이로인해 동적타입이 사용되기 시작했으며 선택적매개변수와 명명된 인수기능이 추가되었습니다.
● 5.0
2012년에 릴리즈 되었으며 비동기구현에 대한 지원이 강화되었습니다. 이로서 비동기를 구현하는것이 매우 간소화되었습니다.
● 6.0
2015년에 릴리즈 되었으며 정적 Import를 통해 console사용을 간소화 할 수 있게 되었습니다. 문자열보간이 도입되어 좀더 형식화된 문자열내용을 출력할 수 있게 되었고 식 본문 멤버의 도입으로 읽기전용 속성 사용이 가능해 지는등 C#언어에 대한 전반적인 구문향상이 이루어졌습니다.
● 7.0
2017년 3월에 릴리즈 되었으며 튜플리나 패턴매칭과 같은 언어기능이 추가되었습니다. 바이너리 리터럴(Binary literals)과 디지트 세퍼레이터(digit separators)를 통해 숫자를 다루는 것에 대한 편의성과 표현력이 강화되었고 out변수와 지역함수등의 기능이 추가되었습니다.
● 7.1
2017년 8월에 릴리즈 되었으며 기본 리터럴 표현식(Default literal expressions), 튜플 리터럴에서 추론된 요소 이름(Inferred tuple element names), 비동기 메인 함수(async Main)기능이 추가되었습니다.
● 7.2
2017년 11월에 릴리즈 되었으며 언더바(_)문자를 사용한 숫자구분기호(Leading underscores in numeric literals)사용이 가능해 졌으며 뒤에 오지 않는 명명된 인수(Non-trailing named arguments), 접근 한정자 (private protected access modifier), 튜플형식에 대한 ==, !=등의 비교가능 기능등이 추가되었습니다.
● 7.3
2018년 5월에 릴리즈되었으며 ref 변수, 포인터(Pointers), stackalloc처럼 안전한 코드의 성능을 안전하지 않은 코드만큼 향상하는데 초점이 맞춰졌습니다.
● 8.0
2019년 9월에 릴리즈 되었으며 Null 가능한 참조 타입(Nullable reference types)등 언어에 대한 주된 변화가 이루어진 버전입니다. 스위치 구문 식(Switch expression)이 가능해졌으며 인터페이스 메서드(Default interface methods)등이 추가되었습니다.
● C# 9.0
2020년 11월에 출시되었으며 레코드 형식(record types) 추가, 패턴 매칭 향상, Top-level programs도입, new 타입 형식(Target-typed new)등이 추가되었습니다.
● C# 10
2021년 11월에 출시되었으며 글로벌 네임스페이스(Global namespace imports)와 같이 일반적인 시나리오에서 필요한 코드를 최소화하기 위한 방법이 도입되었으며 그밖에 상수 문자열 리터럴(Constant string literals), 파일 범위 네임스페이스(File-scoped namespaces), 필수 속성(Required properties), 레코드 구조체(Record structs), Null 매개변수 확인(Null parameter check) 기능이 추가되었습니다.
● C#의 표준화
마이크로소프트는 C#에 대한 몇몇 버전을 표준기관에 제출함으로써 다음과 같은 공식적인 표준화 코드를 부여받았습니다.
C# Version | ECMA | ISO/IEC |
1.0 | ECMA-334:2003 | ISO/IEC 23270:2003 |
2.0 | ECMA-334:2006 | ISO/IEC 23270:2006 |
5.0 | ECMA-334:2017 | ISO/IEC 23270:2018 |
마이크로소프트는 2014년 C#을 오픈소스화 하였으며 현재 3개의 GitHub 라파지토리를 통해 C# 및 그와 관련된 기술개발을 진행하고 있습니다.
주제 | GitHub |
C# 설계 관련 | https://github.com/dotnet/csharplang |
컴파일러 관련 | https://github.com/dotnet/roslyn |
언어에 대한 표준화 관련 | https://github.com/dotnet/csharpstandard |
● C# 컴파일러
C# 컴파일러는 Roslyn으로 알려져 있으며 Visual Basic의 컴파일러 이기도 하지만 F#의 컴파일러와는 또 다릅니다. .NET SDK의 일부로서 배포되었으며 최신버전의 .NET SDK는 하위 호환성을 유지하므로 하위 모든 C#버전에 사용할 수 있습니다.
프로젝트 생성시 .NET Standard 및 특정 .NET 버전을 지정해 생성할 수 있으며 .NET Standard에 따른 기본 C#버전은 다음과 같습니다.
.NET Standard 2.0 | C# 7.3 |
.NET Standard 2.1 | C# 8.0 |
SDK의 버전은 아래와 같은 방법으로 확인해 볼 수 있습니다.
dotnet --version |
보통 일반적인 경우 C#프로젝트는 기본적으로 최신 버전의 C#언어에서 동작하도록 합니다. C# 7.0의 경우에도 7.0 버전을 사용하는 것이 기본이었으므로 만약 7.1, 7.2와 같은 하위 Minor버전을 사용하려 한다면 프로젝트 파일에 다음과 같이 <LangVersion>을 추가시켜야 했습니다.
<LangVersion>7.3</LangVersion>
이렇듯 주요 Major버전 사용이 기본이므로 만약 C# 10.1과 같은 하위 버전이 릴리즈 되고 해당 버전을 사용해야 하는 경우라면 같은 방법으로 사용버전을 지정해 주면 됩니다.
참고로 <LangVersion>에서 사용할 수 있는 버전 값은 10.1이나 7.3처럼 직접적으로 지정하는 대신 다음과 같은 값을 사용할 수도 있습니다.
- latestmajor : Major버전을 기준으로 한 가장 최신의 버전을 사용하도록 합니다.
- latest : Minor버전을 포함하여 가장 최신의 버전을 사용하도록 합니다.
- preview : Preview버전을 포함하여 가장 최신의 버전을 사용하도록 합니다.
Visual Studio Code를 사용하는 경우라면 *.csproj와 같은 프로젝트 파일 편집을 위해 'MSBuild project'확장 기능을 사용할 수 있습니다. 이 확장 도구는 파일 편집 시 유용한 IntelliSense기능을 제공해줄 것입니다.
2. C# 개요
C# 언어를 사용해 보기 전 간단한 Console App프로젝트를 생성하고 Visual Studio Code를 사용해 Program.cs를 열어보는 것으로 시작해 보겠습니다.
Visual Studio Code사용 시 프로젝트는 아래 명령으로 생성할 수 있습니다.
dotnet new console |
생성할 프로젝트의 이름이나 언어를 따로 지정하지 않으면 C#언어를 기반으로 하는 현재 폴더의 이름으로 프로젝트가 생성됩니다. 하지만 다음과 같은 방법으로 사용언어와 프로젝트 이름을 지정해 줄 수도 있습니다.
dotnet new console --lang "C#" --name testproject |
프로젝트가 생성되었으면 우선 현재의 Compiler와 C#언어 Version을 다음의 방법으로 확인해 볼 수 있습니다.
// See https://aka.ms/new-console-template for more information
#error version
Console.WriteLine("Hello, World!");
소스를 위와 같이 수정한 후 마우스를 version에 올려오면 해당 값이 나타나게 됩니다.
Compiler버전은 4.x대 이상, C#은 10 버전 이상이어야 합니다.
● 구문
C#에서 문의 끝은 세미콜론(;)으로 끝나며 다수의 변수의 식으로 구성될 수 있습니다. 예를 들어 아래 문의 경우 sum이라는 변수 하나와 i + j라는 하나의 식을 갖고 있습니다.
int sum = i + j;
예제에서 식은 i와 j라는 피연산자와 +라는 연산자로 구성되어 있습니다.
● 주석
주석은 코드를 설명하기 위한 부분으로 //로 시작할 수 있으며 compiler는 //부터 해당 문장의 끝까지 모든 것을 무시하고 진행하게 됩니다.
// See https://aka.ms/new-console-template for more information
Console.WriteLine("Hello, World!");
만약 다수의 라인에 걸쳐 주석을 써야 한다면 //대신 /* 과 */을 사용할 수 있습니다. compiler는 /*부터 */까지 모든 내용을 무시합니다.
/* See https://aka.ms/new-console-template for more information
See https://aka.ms/new-console-template for more information */
Console.WriteLine("Hello, World!");
● Block
C#에서 Block는 {로 시작하고 }로 끝날 수 있고 해당 Block안에는 namespace나 class, method 그리고 foreach와 같은 식을 포함할 수 있습니다.
using System;
namespace test
{
class Program
{
static void Main(string[] args)
{
Console.WriteLine("abc");
}
}
}
● C#에서 사용되는 단어와 어휘들
C#에서 어휘/단어는 키워드나 기호 문자, 형식 등을 의미합니다. 이 중에서 키워드는 namespace, class, static, int, string, double, bool, if, switch, break, while, do, for, foreach, and, or, not, record, init와 같은 단어들이며 C#언어 안에서 특수한 용도로 사용될 목적으로 사전 정의된 단어들에 해당합니다.
또한 연산이나 결합 등의 목적으로 ", ', +, -, *, /, %, @, $와 같은 특수문자가 사용될 수 있습니다. 이 밖에도 많은 단어나 어휘들이 특수한 용도로 사용될 수 있습니다. 물론 이들 단어 전체를 모두 외워둘 필요가 전혀 없으며 C#언어의 구문을 작성하면서 자연스럽게 익혀질 것입니다.
● Namespace
예제의 'using System;'에서 System은 Namespace에 해당합니다. Namespace는 타입의 주소와 같은 것으로 정확히 무엇을 참조해야 할지를 나타냅니다.
System.Console.WriteLine은 compiler에게 WriteLine메서드가 System안에 Console형식에 있음을 말해주는 것으로 이를 간소화하기 위해 System을 Namespace로 Import 해주면 Console.WriteLine만으로 WriteLine메서드를 호출할 수 있게 되는 것입니다.
.NET6이전에는 모든 파일에 기본으로 'using Sytem;'등을 붙여 왔지만 .NET6부터는 Global Namespace도입으로 하나의 파일에서만 'global using global::System;'처럼 기본적으로 사용되는 Namespace를 Import 하기 시작했습니다.
이 기능은 .NET 6.0과 C#10을 기반으로 하는 프로젝트에서만 적용되며 어떤 Namespace가 Import 되는지는 프로젝트에서 사용하는 SDK에 의존하여 정해집니다.
SDK | imported namespaces |
Microsoft.NET.Sdk | System System.Collections.Generic System.IO System.Linq System.Net.Http System.Threading System.Threading.Tasks |
Microsoft.NET.Sdk.Web | System.Net.Http.Json Microsoft.AspNetCore.Builder Microsoft.AspNetCore.Hosting Microsoft.AspNetCore.Http Microsoft.AspNetCore.Routing Microsoft.Extensions.Configuration Microsoft.Extensions.DependencyInjection Microsoft.Extensions.Hosting Microsoft.Extensions.Logging |
Microsoft.NET.Sdk.Worker | Microsoft.Extensions.Configuration Microsoft.Extensions.DependencyInjection Microsoft.Extensions.Hosting Microsoft.Extensions.Logging |
참고로 Microsoft.NET.Sdk.Web과 Microsoft.NET.Sdk.Worker는 Microsoft.NET.Sdk의 Namespace 목록을 기본으로 Import 합니다.
실제 Import 된 Namespace의 목록을 확인해 보려면 프로젝트 폴더의 'obj/Debug/net6.0'폴더 안에서 '[프로젝트명]. GlobalUsings.g.cs'파일을 열어보면 확인할 수 있습니다. 해당 파일은 Compiler에 의해 자동으로 생성됩니다.
// <auto-generated/>
global using global::Microsoft.AspNetCore.Builder;
global using global::Microsoft.AspNetCore.Hosting;
global using global::Microsoft.AspNetCore.Http;
global using global::Microsoft.AspNetCore.Routing;
global using global::Microsoft.Extensions.Configuration;
global using global::Microsoft.Extensions.DependencyInjection;
global using global::Microsoft.Extensions.Hosting;
global using global::Microsoft.Extensions.Logging;
global using global::System;
global using global::System.Collections.Generic;
global using global::System.IO;
global using global::System.Linq;
global using global::System.Net.Http;
global using global::System.Net.Http.Json;
global using global::System.Threading;
global using global::System.Threading.Tasks;
만약 위와 같은 상황에서 특정 Namespace의 선언을 추가하거나 삭제하려면 프로젝트 파일(*. csproj)을 다음과 같이 수정하여 필요한 Namespace를 설정할 수 있습니다.
<ItemGroup>
<Using Remove="System.Threading" />
<Using Include="System.Numerics" />
</ItemGroup>
자동으로 Namespace가 Global로 Import 되는 기능 자체를 막고자 한다면 아래 entry를 찾아 삭제할 수 있습니다.
<ImplicitUsings>enable</ImplicitUsings>
C#10에서는 Namespace Import를 간소화하기 위한 또 다른 방법으로 임의의 Namespace를 다음과 같이 global로 Import 할 수 있는 기능을 제공하고 있습니다.
global using System;
이 방법은 Program.cs에서 구현하거나 GlobalNamespaces.cs와 같은 별도의 파일을 만들어 사용하면 됩니다.
● 메서드(Method)
메서드는 프로그램에서 특정 기능을 동작하기 위한 것입니다. 예를 들어 'Console.WriteLine("Hello");'처럼 WriteLine() 메서드를 호출하면 화면에 지정된 문자열인 Hello를 표시할 것입니다. 이때 같은 메서드라 하더라도 메서드를 어떻게 호출하느냐에 따라 그 동작이 달리질 수 있습니다. 흔히 메서드를 '오버 로딩'한다고 하는 것인데
Console.WriteLine("Hello {0}", userName);
처럼 하면 userName이라는 변숫값이 'cliel'인 경우 'Hello cliel'처럼 다소 동적인 내용을 표시할 수 있게 되는 것입니다.
● 타입(types)
C#에서는 string이나 int처럼 사용 가능한 수많은 type들이 존재합니다. 그러나 C#언어 자체가 이들 type을 정의하는 것이 아니고 C#언어가 동작하는 플랫폼에서 제공하는 특정 타입을 표현하기 위한 별칭을 사용할 뿐입니다. string이나 int도 마찬가지입니다.
.NET이라는 플랫폼은 C#언어를 위해 사용 가능한 많은 type들을 제공하고 있고 C#은 그저 제공되는 type을 사용하기 위해 별칭을 사용하는데 예를 들어 'System.Int32'와 같은 type이 제공되는 경우라면 int라는 별칭을 통해 해당 type을 연결해 사용하는 것입니다.
C#에서 사용가능한 type(혹은 메서드)가 얼마나 존재하는지에 대해서는 아래와 같은 간단한 Console App을 통해 Reflection을 구현함으로써 확인할 수 있습니다.
using System.Reflection;
Assembly? assembly = Assembly.GetEntryAssembly();
if (assembly is null)
return;
foreach (AssemblyName name in assembly.GetReferencedAssemblies())
{
Assembly asem = Assembly.Load(name);
int methodCount = 0;
foreach (TypeInfo t in asem.DefinedTypes)
methodCount += t.GetMethods().Count();
Console.WriteLine(name.Name);
Console.WriteLine($"Type : {asem.DefinedTypes.Count()}");
Console.WriteLine($"Method : {methodCount}");
Console.WriteLine("---------------------------------------------");
}
다른 Assembly 쪽으로 확인이 필요하다면 해당 Assembly를 참조하는 변수 등을 아래와 같이 추가해 주면 됩니다.
HttpClient a;
'.NET > C#' 카테고리의 다른 글
[C#] C# 개요 - 3. 기타 Console Application 관련 (0) | 2022.06.24 |
---|---|
[C#] C# 개요 - 2. 변수 (0) | 2022.06.24 |
[C#] C#과 .NET6 시작하기 - 3. Console App 만들어 보기 (0) | 2022.06.24 |
[C#] C#과 .NET6 시작하기 - 2. .NET 이해하기 (0) | 2022.06.24 |
[C#] C#과 .NET6 시작하기 - 1. 개발환경설정 (0) | 2022.06.24 |