C# 8.0의 새로운 기능 10가지 소개

  • 4 minutes to read

소개

이번 실습 예제에서는 하나의 .NET Core 기반의 C# 프로젝트를 만들고 C# 8.0의 주요 특징 10가지를 모두 적용하는 예제를 만들어보겠습니다.

따라하기 0: .NET Core 7.0 기반의 C# 콘솔 프로젝트 생성하기

(1) SeeSharp.Eight 이름으로 .NET Core 7.0 이상으로 C# 콘솔 앱 프로젝트를 생성합니다.

(2) SeeSharp.Eight 프로젝트에 마우스 오른쪽 버튼을 클릭 후 [Edit Project File] 메뉴를 선택하여 csproj 파일의 편집 화면으로 들어갑니다.

(3) SeeSharp.Eight 파일의 여러 항목 중에서 <PropertyGroup> 섹션에 <Nullable> 항목이 enable로 되어 있는지 확인 또는 없으면 다음 샘플 코드와 같이 추가합니다.

코드: SeeSharp.Eight.csproj

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

  <PropertyGroup>
    <TargetFramework>netcoreapp3.0</TargetFramework>
    <IsPackable>false</IsPackable>
    <Nullable>enable</Nullable>
  </PropertyGroup>

</Project>

따라하기 1: C# 8.0의 새로운 기능 10가지가 적용된 코드 작성

200 줄 가까이되는 다음 코드는 작성 후 실행해보세요

좀 더 빠른 이해를 위해서 다음 경로에 미리보기 동영상을 올려두었습니다.

코드: DotNet\SeeSharp.Eight\Program.cs

//[?] C# 8.0의 새로운 기능 10가지
using System;
using System.Collections.Generic;
using System.Threading.Tasks;

namespace SeeSharp.Eight
{
    // Interface
    public interface IEmployee
    {
        public string Name { get; }
        public decimal Salary { get; }
        //[!] C# 8.0: Default interface members
        public string Id { get => $"{Name}[{this.GetHashCode()}]"; }
    }

    // Class
    public class Person
    {
#nullable disable
        public string Name { get; }
        public Person(string name) => Name = name;

        //[!]
        public string FirstName { get; set; }
        public string MiddleName { get; set; }
        public string LastName { get; set; }
#nullable enable

        public Person(string first, string last)
        {
            FirstName = first;
            MiddleName = null;
            LastName = last;
        }

        public Person(string first, string middle, string last)
        {
            FirstName = first;
            MiddleName = middle;
            LastName = last;
        }
    }

    // Abstract Class
    public abstract class Employee : Person, IEmployee
    {
        public Employee(string name, decimal salary)
            : base(name) => Salary = salary;
        public decimal Salary { get; protected set; }
    }

    public class Professor : Employee, IEmployee
    {
        public string Topic { get; }
        public Professor(string name, decimal salary, string topic)
            : base(name, salary) => Topic = topic;

        // TODO: Deconstruct() Method => C# 7.0 User-Defined Types Deconstructing
        public void Deconstruct(out string name, out string topic)
            => (name, topic) = (Name, Topic);

        //[?] Indices and ranges
        //public string Id => $"{Name}[{Topic[0..3]}]";
        public string Id => $"{Name}[{Topic[..3]}~{Topic[^3..^0]}]";
    }

    public class Administrator : Employee
    {
        public string Department { get; }
        public Administrator(string name, decimal salary, string department)
            : base(name, salary) => Department = department;
    }

    public static class Service
    {
#nullable disable
        static Person[] people = null;
#nullable enable

        static Service()
        {
            //[?] Null Coalescing Assignment Operator: ??= 
            people ??= new Person[]
            {
                new Professor("RedPlus", 1______000, "Computer Science"),
                new Administrator("Taeyo", 2_000, "ABC"),
                new Professor("Itist", 3_000, "Computer Science")
            };
        }

        public static IEnumerable<IEmployee> GetEmployees()
        {
            foreach (var person in people)
            {
                if (person is IEmployee employee)
                {
                    yield return employee;
                }
            }
        }

        //[?] C# 8.0 Asynchronous streams
        public static async IAsyncEnumerable<IEmployee> GetEmployeesAsync()
        {
            foreach (var person in people)
            {
                await Task.Delay(500);
                if (person is IEmployee employee) yield return employee;
            }
        }
    }

    class Program
    {
        static async Task Main(string[] args)
        {
            //[?] C# 8.0 - Static Local Function
            static void Print(string message) => Console.WriteLine(message);

            //[A] Synchronous 
            foreach (var employee in Service.GetEmployees())
            {
                Print($"Name: {employee.Name}");
            }
            Print("========================================");
            foreach (var employee in Service.GetEmployees())
            {
                //[?] Pattern Matching: C# 7.0 Type Pattern
                if (employee is Administrator administrator
                    && administrator.Department is "ABC")
                {
                    Print($"Administrator: {administrator.Name}");
                }
            }
            Print("========================================");

            //[B] Asynchronous
            await foreach (var employee in Service.GetEmployeesAsync())
            {
                //[?] Pattern Matching: C# 8.0 Property Pattern, Var Pattern 
                if (employee is Professor
                {
                    Topic: "Computer Science", Name: var name
                } professor)
                {
                    Print($"Professor: {name} ({professor.Id})");
                }
            }
            await foreach (var employee in Service.GetEmployeesAsync())
            {
                //[?] Pattern Matching: C# 8.0 Location Pattern
                if (employee is Professor(var name, "Computer Science") professor)
                {
                    Print($"Professor: {name} ({professor.Id})");
                }
            }

            //[?] C# 8.0 - Nullable Reference Type
            var red = new Person("YJ", "Park");
            var length = GetMiddleNameLength(red);
            Console.WriteLine(length); // 0 

            //[?] Switch Expression
            Print("========================================");
            await foreach (var employee in Service.GetEmployeesAsync())
            {
                Console.WriteLine(GetDetails(employee));
            }

            static string GetDetails(IEmployee person)
            {
                return person switch
                {
                    Professor p when p.Salary > 1_000 => $"{p.Name}-{p.Topic}-Big",
                    Professor p => @$"{p.Name} - {p.Topic}",
                    Administrator a => $"{a.Name} - {a.Department}",
                    _ => $@"Who are you?"
                };
            }
        }

        static int GetMiddleNameLength(Person? person)
        {
            //[?] is somthing
            if (person?.MiddleName is { } middle) return middle.Length;
            return 0; // is null 
        }
    }
}
Name: RedPlus
Name: Taeyo
Name: Itist
========================================
Administrator: Taeyo
========================================
Professor: RedPlus (RedPlus[Com~nce])
Professor: Itist (Itist[Com~nce])
Professor: RedPlus (RedPlus[Com~nce])
Professor: Itist (Itist[Com~nce])
0
========================================
RedPlus - Computer Science
Taeyo - ABC
Itist-Computer Science-Big

C:\DotNet\DotNet\DotNet\SeeSharp.Eight\bin\Debug\netcoreapp3.0\SeeSharp.Eight.exe (process 30252) exited with code 0.
Press any key to close this window . . .
VisualAcademy Docs의 모든 콘텐츠, 이미지, 동영상의 저작권은 박용준에게 있습니다. 저작권법에 의해 보호를 받는 저작물이므로 무단 전재와 복제를 금합니다. 사이트의 콘텐츠를 복제하여 블로그, 웹사이트 등에 게시할 수 없습니다. 단, 링크와 SNS 공유, Youtube 동영상 공유는 허용합니다. www.VisualAcademy.com
박용준 강사의 모든 동영상 강의는 데브렉에서 독점으로 제공됩니다. www.devlec.com