[C#] 기초 문법 총정리

Eugene CHOI·2021년 4월 24일
0

C#

목록 보기
1/1


이 글은 C# Textbook이라는 책의 내용을 정리한 흔적입니다.


코드 에디터에서 Ctrl+E,E를 누르면 인터렉티브 모드로 들어갈 수 있다.

개발자 명령 프롬프트에서 CSI라고 입력하여도 가능하다.

자료형의 여러가지 속성 값 확인

Console.WriteLine(Single.MaxValue);
Console.WriteLine(Single.MinValue);
Console.WriteLine(float.MaxValue);
Console.WriteLine(float.MinValue);
Console.WriteLine(double.MaxValue);
Console.WriteLine(double.MinValue);
Console.WriteLine(int.MaxValue);
Console.WriteLine(int.MinValue);
Console.WriteLine(typeof(string).IsPrimitive);
  • 결과

여러가지 변수 사용법

float f = 3.14f;
double d = 3.14;
double dd = 3d;
decimal dec = 3.14m;

uint ui = 3200u;
ulong u = 3200ul;

bool b = true;

문자, 문자열, 문자열 보간법, 문자열 템플릿, 템플릿 문자열

char c = 'A';

string s = "ABC";
string ss = @"안녕하세요
반갑습니다."; // 여러 줄 문자열
string msg = $"{f}/{ui}={f / ui}";
string msg2 = string.Format("{0}님, {1}", "최호승", "안녕하세요");
string msg4 = "최호승님" + ", 안녕하세요";

닷넷 데이터 형식, 래퍼 형식

System.Char C = 'A';
System.String S = "ABC";
System.Boolean B = false;

콘솔 입력받기

string s = Console.ReadLine();
Console.WriteLine(s);
int c = Console.Read(); // 입력값이 정수로 들어간다.
Console.WriteLine(c);
  • 결과

형변환

int n1 = 1234;
long n2 = n1; // 암시적 형변환
int n3 = (int)n2; // 명시적 형변환, 명시적으로 하지 않으면 오류
string s1 = Convert.ToString(n3); // Convert 클래스 이용

데이터 타입 확인

string s = "1234";
int n1 = Convert.ToInt32(s);
int n2 = int.Parse(s);
int n3 = System.Int32.Parse(s);
Console.WriteLine($"{n1}-{n1.GetType()}");
Console.WriteLine($"{n2}-{n2.GetType()}");
Console.WriteLine($"{n3}-{n3.GetType()}");
  • 결과

진법 변환 및 타입 추론

int num = 15;
string s1 = Convert.ToString(num, 2); // 10진수 -> 2진 문자
string s2 = Convert.ToString(num, 2).PadLeft(8, '0');
Console.WriteLine(s1);
Console.WriteLine(s2); // 8칸 기준으로 출력하고 앞부분은 0으로 채운다.

string s = "1011011";
int n = Convert.ToInt32(s, 2); // 2진 문자 -> 10진수
Console.WriteLine(n);

byte b1 = 0b11001; // 2진수 리터럴
int h = 0x11001; // 16진수 리터럴

int dec = 1_000_000; // 1,000,000
int hex = 0xA0_B6_C3; // A0B6C3

var n1 = 1234; // 형식 추론, type inference, 컴파일 타임에 타입 결정
dynamic n2 = 33; // 런타임 타임에 타입 결정
n2 = "great"; // 다이나믹 타입만 타입 변경이 가능
  • 결과

콘솔에서 키 입력 받기

Console.WriteLine("아무키나 누르세요.");
ConsoleKeyInfo cki = Console.ReadKey(true);
Console.WriteLine($"{cki.Key}");
Console.WriteLine($"{cki.KeyChar}");
Console.WriteLine($"{cki.Modifiers}");
if(cki.Key == ConsoleKey.Q)
{
    Console.WriteLine("Q를 입력하셨습니다.");
}
  • 결과

변수의 초기값을 기본값으로 설정하기

int i = default;
double d = default;
char c = default;
string s = default;
Console.WriteLine($"[{i}], [{d}], [{c}], [{s}]");
Console.WriteLine($"[{i}], [{d}], [{c == '\0'}], [{s == null}]");
  • 결과

덧셈 연산자

Console.WriteLine("123" + "456");
Console.WriteLine("123" + 456); // 문자열로 취급, 뺄셈은 에러가 발생
Console.WriteLine(123 + 456);
  • 결과

if문: out var 구문의 사용법

string s = "1234";
if (int.TryParse(s, out var result))
{
    Console.WriteLine("inner {0}",  result);
}
Console.WriteLine("outter {0}", result); // 외부에서도 사용 가능
  • 결과

foreach 구문

string s = "ABCDEFG";
foreach(char c in s)
{
    Console.Write($"{c}\t");
}
  • 결과

배열

1차원 배열

int[] array1 = new int[3] { 1, 2, 3 }; // 배열
var array2 = new int[] { 1, 2, 3 }; // 배열 축약
Console.WriteLine($"배열의 크기: {array1.Length}");
Console.WriteLine($"배열의 용량: {Buffer.ByteLength(array1)}");
  • 결과

2차원 배열

int[,] array1 = new int[2, 3] { { 1, 2, 3 }, { 4, 5, 6 } }; // 2차원 배열 선언법1
int[,] array2 = new int[,] { { 1, 2, 3 }, { 4, 5, 6 } }; // 2차원 배열 선언법2
int[,] array3 = { { 1, 2, 3 }, { 4, 5, 6 } }; // 2차원 배열 선언법3

3차원 배열

int[,,] array1 = new int[2, 2, 2] { { { 1, 2 }, { 3, 4 } }, { { 5, 6 }, { 7, 8 } } }; // 2차원 배열 선언법1
int[,,] array2 = new int[,,] { { { 1, 2 }, { 3, 4 } }, { { 5, 6 }, { 7, 8 } } }; // 2차원 배열 선언법2
int[,,] array3 = { { { 1, 2 }, { 3, 4 } }, { { 5, 6 }, { 7, 8 } } }; // 2차원 배열 선언법3

Console.WriteLine("차수: {0}", array1.Rank);
Console.WriteLine("길이: {0}", array1.Length);
Console.WriteLine("페이지 크기: {0}", array1.GetLength(0));
Console.WriteLine("행 크기: {0}", array1.GetLength(1));
Console.WriteLine("열 크기: {0}", array1.GetLength(2));
  • 결과

동적 배열

int[][] zagArray = new int[2][]; // 열을 비워두면 동적으로 자료 n개로 초기화 가능
zagArray[0] = new int[] { 1, 2 };
zagArray[1] = new int[] { 3, 4, 5 };
for (int i = 0; i < zagArray.GetLength(0); i++)
{
    for (int j = 0; j < zagArray[i].Length; j++)
    {
        Console.Write($"{zagArray[i][j]}\t");
    }
    Console.WriteLine();
}
  • 결과

함수

함수, xml 문서 주석, 기본 매개변수, 명명된 매개변수, 오버로딩

static void Main(string[] args)
{
    int r = Square(x: 3); // 명명된 매개변수
    Console.WriteLine(r);
}

/// <summary>
/// 파라미터의 제곱 수를 반환하는 함수
/// </summary>
/// <param name="x">정수형의 매개변수</param>
/// <returns>x^2</returns>
static int Square(int x = 1) // 기본 매개변수
{
    int r = x * x;
    return r;
}

static double Square(double x = 1.0) // 오버로딩
{
    double r = x * x;
    return r;
}

지역변수와 전역변수

static string msg = "전역변수";
static void Main(string[] args)
{
    showmsg();
    Console.WriteLine(msg) ;
}

static void showmsg()
{
    string msg = "지역변수";
    Console.WriteLine(msg);
}
  • 결과

람다식 (화살표 메서드, ⇒, 식 본문 메서드)

static void Main(string[] args)
{
    Hi();
    Mul(3, 4);
}
static void Hi() => Console.WriteLine("안녕하세요");
static void Mul(int a, int b) => Console.WriteLine(a*b);
  • 결과

로컬 함수

static void Main(string[] args)
{
    void Display(string text)
    {
        Console.WriteLine(text);
    }
		void Add(int a, int b) => a+b;

    Display("로컬 함수");
		Console.WriteLine($"3+5={Add(3,5)}");
}

명령 줄 인수

static void Main(string[] args)
{
    foreach (string s in args)
    {
        Console.WriteLine(s);
    }
}
  • 결과

.Net API 맛보기

닷넷 API, Math 클래스

Console.WriteLine(Math.PI);
Console.WriteLine(Math.E);

Console.WriteLine(Math.Abs(-3.14));
Console.WriteLine(Math.Max(3, 6));
Console.WriteLine(Math.Min(3, 6));

// 매개변수가 동일하다면 같은 결과를 반환하는 함수를 순수 함수라고 한다.
Console.WriteLine(Math.Pow(3, 2));
Console.WriteLine(Math.Sqrt(9));

// 랜덤은 비순수 함수이다.
Console.WriteLine((new Random()).Next());

Console.WriteLine(Math.Ceiling(-3.14));
Console.WriteLine(Math.Floor(-3.14));
Console.WriteLine(Math.Round(-3.14));
Console.WriteLine(Decimal.Ceiling(3.14m));
Console.WriteLine(Math.Floor(3.14m));
Console.WriteLine(Math.Round(3.14m));
  • 결과

클래스 또는 메서드 이름을 문자열로 가져오기

int a = 33;
Console.WriteLine(nameof(a));
Console.WriteLine(nameof(Math));
Console.WriteLine(nameof(System.Console));
  • 결과

구조체

구조체 선언 및 사용

public int X; // 기본 엑세스 한정자는 private이다.
    public int Y;
}
static void Main(string[] args)
{
    Point p;
    p.X = 100;
    p.Y = 200;
    Console.WriteLine($"{p.X}, {p.Y}");
}

구조체에서 생성자 만들어 한번에 초기화하기

struct Point
{
    public int X; // 기본 한정자는 private이다.
    public int Y;

    public Point(int _x, int _y)
    {
        this.X = _x;
        this.Y = _y;
    }
}
static void Main(string[] args)
{
    Point p = new Point(100, 200);
    Console.WriteLine($"{p.X}, {p.Y}");
}

DateTime 구조체 사용하기

Console.WriteLine($"현재 시간: {DateTime.Now}");
Console.WriteLine(DateTime.Now.Year);
Console.WriteLine(DateTime.Now.Month);
Console.WriteLine(DateTime.Now.Day);
Console.WriteLine(DateTime.Now.Hour);
Console.WriteLine(DateTime.Now.Minute);
Console.WriteLine(DateTime.Now.Second);
Console.WriteLine(DateTime.Now.Millisecond);
  • 결과

DateTime으로 시간 얻기

DateTime now = DateTime.Now;
Console.WriteLine(now.ToShortTimeString());
Console.WriteLine(now.ToLongTimeString());
  • 결과

남은 날짜와 지난 날자 계산하기

TimeSpan dday = Convert.ToDateTime("2021-12-25") - DateTime.Now; // 남은 날짜
Console.WriteLine($"21년 크리스마스 까지 {dday.TotalDays:0.}일 남았습니다.");

TimeSpan times = DateTime.Now - Convert.ToDateTime("1995-08-17"); // 지난 날짜
Console.WriteLine($"출생일로부터 {times.TotalDays:0.}일 지났습니다.");
  • 결과

날짜를 파싱하여 출력하기

if (DateTime.TryParse("2019/12/25", out var xmas)) // 인라인 out 변수
{
    Console.WriteLine(xmas); // 날짜를 파싱하여 출력
}
  • 결과

정수에 해당하는 날짜를 반환하는 함수 만들기

static void Main(string[] args)
{
    Console.WriteLine(GetDateTimeFromYearlyHourNumber(1));
    Console.WriteLine(GetDateTimeFromYearlyHourNumber(8760/2));
    Console.WriteLine(GetDateTimeFromYearlyHourNumber(8760));
}
static DateTime GetDateTimeFromYearlyHourNumber(int number)
{
    return (new DateTime(2021, 1, 1, 0, 0, 0).AddHours(--number));
}
  • 결과

Char 구조체

char a = 'A';
char b = 'a';
char c = '1';
char d = '\t';
if (Char.IsUpper(a))
{
    Console.WriteLine("{0}은 대문자", a);
}
if (Char.IsLower(b))
{
    Console.WriteLine("{0}은 소문자", b);
}
if (Char.IsNumber(c))
{
    Console.WriteLine("{0}은 숫자", c);
}
if (Char.IsWhiteSpace(d))
{
    Console.WriteLine("{0}은 공백", d);
}
  • 결과

Guid(Globally Unique IDentifier) 구조체 사용하기

Guid는 유일한 값을 의미한다. 실행할 때마다 동일한 값을 만날 확률이 0이다.

string unique = Guid.NewGuid().ToString();
Console.WriteLine(unique);
Console.WriteLine($"D옵션 유일한 값: {Guid.NewGuid().ToString("D")}");
Console.WriteLine($"N옵션 유일한 값: {Guid.NewGuid().ToString("N")}");
Console.WriteLine($"B옵션 유일한 값: {Guid.NewGuid().ToString("B")}");
Console.WriteLine($"P옵션 유일한 값: {Guid.NewGuid().ToString("P")}");
Console.WriteLine($"X옵션 유일한 값: {Guid.NewGuid().ToString("X")}");
  • 결과

열거형

ConsoleColor 열거형으로 콘솔 색 바꾸기

Console.ForegroundColor = ConsoleColor.Blue; // 전경색
Console.WriteLine("Blue");
Console.ResetColor(); // 컬러 초기화

Console.BackgroundColor = ConsoleColor.Yellow; // 배경색
Console.ForegroundColor = ConsoleColor.Red; // 전경색

Console.WriteLine("Red");
Console.ResetColor();
  • 결과

열거형 직접 만들기

enum Priority
{
    High = 3,
    Normal = 6,
    Low
}
static void Main(string[] args)
{
    Priority high = Priority.High;
    Priority normal = Priority.Normal;
    Priority low = Priority.Low;

    Console.WriteLine($"{high}, {normal}, {low}");
    Console.WriteLine($"{(int)high}, {(int)normal}, {(int)low}");
}
  • 결과

열거형의 상수 리스트를 배열로 가져오기

Type cc = typeof(ConsoleColor);
string[] colors = Enum.GetNames(cc);
foreach (var color in colors)
{
    Console.WriteLine(color);
}
  • 결과

문자열을 특정 열거형으로 변환하기

string color = "Red";
Console.ForegroundColor = (ConsoleColor)Enum.Parse(typeof(ConsoleColor), color);
Console.WriteLine("Red");
Console.ResetColor();

클래스 맛보기

정적 메서드와 인스턴스 메서드

class Program
{
    static void staticMethod() => Console.WriteLine("static method");
    void instanceMethod() => Console.WriteLine("instance method");

    static void Main(string[] args)
    {
        Program.staticMethod();
        Program myclass = new Program();
        myclass.instanceMethod();
        
    }
}

Environment 클래스로 프로그램 강제 종료

static void Main(string[] args)
{
    Console.WriteLine("시작합니다.");
    Environment.Exit(0); // 인수는 exit code이다.
    Console.WriteLine("출력이 될까요?");
    
}
  • 결과

환경 변수 사용하기

Console.WriteLine(Environment.SystemDirectory);
Console.WriteLine(Environment.Version);
Console.WriteLine(Environment.OSVersion);
Console.WriteLine(Environment.MachineName);
Console.WriteLine(Environment.UserName);
Console.WriteLine(Environment.CurrentDirectory);
Console.WriteLine(Environment.SpecialFolder.MyDocuments);
  • 결과

Process 클래스를 이용하여 EXE 파일 실행하기

using System;
using System.Diagnostics;
namespace cs_testing
{
    class Program
    {
        static void Main(string[] args)
        {
            Process.Start("Notepad.exe");
            Process.Start("Explorer.exe", "https://naver.com");
        }
    }
}

Random 클래스 사용하기

Random random = new Random();
Console.WriteLine(random.Next());
Console.WriteLine(random.Next(5)); // 0~4
Console.WriteLine(random.Next(1,10)); // 1~10
Console.WriteLine(random.NextDouble()); // 0~1 사이의 실수
  • 결과

Stopwatch 클래스를 사용하여 프로그램 실행 시간 측정하기

using System;
using System.Diagnostics;
using System.Threading;

namespace cs_testing
{
    class Program
    {
        static void Main(string[] args)
        {
            Stopwatch timer = new Stopwatch();
            timer.Start();
            Thread.Sleep(3000);
            timer.Stop();
            Console.WriteLine($"경과시간: {timer.Elapsed.TotalMilliseconds}");
            Console.WriteLine($"경과시간: {timer.ElapsedMilliseconds}");
            Console.WriteLine($"경과시간: {timer.ElapsedTicks}");

        }
    }
}
  • 결과

정규식 (Regular Expression)

Regex 클래스를 사용하여 하나 이상의 공백을 하나의 공백으로 대체하는 정규식 사용

using System;
using System.Text.RegularExpressions;

namespace cs_testing
{
    class Program
    {
        static void Main(string[] args)
        {
            string s = "안녕하세요. 반갑습니다.                  또 만나요.";
            var regex = new Regex("\\s+"); // "\s"는 공백을 의미한다.
            string r = regex.Replace(s, " ");
            Console.WriteLine(s);
            Console.WriteLine(r);

        }
    }
}
  • 결과

정규 표현식 사용해서 이메일 형식 검증하기

using System;
using System.Text.RegularExpressions;

namespace cs_testing
{
    class Program
    {
        static void Main(string[] args)
        {
            string email1 = "ecanus9@gmail.com";
            string email2 = "ecanus9";
            Console.WriteLine(isEmail(email1));
            Console.WriteLine(isEmail(email2));
        }
        static bool isEmail(string email)
        {
            var regex = new Regex(
                @"^[A-Za-z0-9](([_\.\-]?[a-zA-Z0-9]+)*)@([A-Za-z0-9]+)" +
                @"(([\.\-]?[a-zA-Z0-9]+)*)\.([A-Za-z]{2,})$");
            bool result = regex.IsMatch(email);
            return result;
        }
    }
}
  • 결과

박싱과 언박싱

  • 박싱: 값 형식의 데이터 → 참조 형식의 데이터로 변환하는 작업
int i = 1234;
object o = 1;
  • 언박싱: 참조 형식의 데이터 → 값 형식의 데이터로 변환하는 작업
object o = 1234;
int i = (int)o; // o as int

is와 as 연산자로 형식 비교하기

is연산자: 개체.GetType() == typeof(형식)의 줄임 표현으로 다음과 같이 사용한다.

개체 is 형식

변수 is 데이터 형식

as연산자: 변환이 가능하면 변환하고, 그렇지 않으면 null을 반환한다.

static void Main(string[] args)
{
    isWhat(1234);
    isWhat("Hello");
    isWhat(DateTime.Now);

    object x = 1234;
    string s = x as string;
    Console.WriteLine(s == null? "null":s);
}

static void isWhat(object o)
{
    if (o is int)
        Console.WriteLine("Int");
    else if (o is string)
        Console.WriteLine("String");
    else if (o is DateTime)
        Console.WriteLine("DateTime");
}
  • 결과

문자열

메서드 체이닝: 개체 하나에서 메서드를 여러 번 호출하는 방법을 method chain, method chaining, pipelines라고 한다.

"  Hello ".Replace("Hello", "Hi").TrimStart().TrimEnd().Trim()

문자열을 연결하는 여러가지 방법

char[] charArray = { 'A', 'B', 'C' };
string last = "최";
string first = "호승";

string s1 = new string(charArray);
string s2 = String.Concat(charArray);
string s3 = String.Concat(last, first);
string s4 = last + first;
string s5 = string.Format("이름 : {0}{1}", last, first);
string s6 = $"이름 : {last}{first}"; //문자열 보간법
Console.WriteLine(s1);
Console.WriteLine(s2);
Console.WriteLine(s3);
Console.WriteLine(s4);
Console.WriteLine(s5);
Console.WriteLine(s6);
  • 결과

문자열의 대소문자 비교하기

var s1 = "RedPlus";
var s2 = "redplus";
if (s1 == s2)
    Console.WriteLine("[0] 같습니다.");
if (s1.ToLower() == s2.ToLower())
    Console.WriteLine("[1] 같습니다.");
if (string.Equals(s1, s2, StringComparison.InvariantCultureIgnoreCase))
    Console.WriteLine("[2] 같습니다."); // 고정 문화권 비교
if (string.Equals(s1, s2, StringComparison.OrdinalIgnoreCase))
    Console.WriteLine("[3] 같습니다."); // 서수 비교

ToCharArray()를 사용하여 문자열을 문자 배열로 변환하기

string s = "Christmas";
char[] ch = s.ToCharArray();

foreach (var c in ch)
{
    Console.Write($"{c}\t");
}
  • 결과

Split() 메서드를 사용하여 문자열 분리하기

string s = "Red, Green, Blue";
string[] colors = s.Split(", ");

foreach (var color in colors)
    Console.WriteLine(color);
  • 결과

문자열의 null 값 및 빈 값 체크하기

string s1 = "";
string s2 = String.Empty;
if (s2 == null || s2 == "")
    Console.WriteLine("[1] null 또는 빈 값입니다."); // null + ""
if (string.IsNullOrEmpty(s2))
    Console.WriteLine("[2] null 또는 빈 값입니다."); // null + ""
if(string.IsNullOrWhiteSpace(s2))
    Console.WriteLine("[3] null 또는 빈 값입니다."); // null + "" + " "

기타 문자열 메서드

string s = "Deffer";
Console.WriteLine(s.Replace(s, "디퍼")); // 특정 문자열로 변경
Console.WriteLine(s.IndexOf('e')); // 첫 'e' 문자의 인덱스
Console.WriteLine(s.LastIndexOf('e')); // 마지막 'e' 문자의 인덱스
Console.WriteLine(s.Substring(2,2)); // 2번째 인덱스로부터 두 글자를 읽는다.
Console.WriteLine(s.Substring(2)); // 2번째 인덱스부터 모든 문자열을 반환
Console.WriteLine(s.Remove(2,2)); // 2번째 인덱스로부터 두 글자를 제거한다.
Console.WriteLine(s.StartsWith("De")); // 특정 문자열로 시작하는지 검증한다.
Console.WriteLine(s.EndsWith("er")); // 특정 문자열로 끝나는지 검증한다.
Console.WriteLine(s.PadLeft(10, 'G')); // 특정 문자를 왼쪽에 채운다.
Console.WriteLine(s.PadRight(10, '0')); // 특정 문자를 오른쪽에 채운다.
  • 결과

StringBuilder 클래스: 문자열을 추가 및 삭제가 빈번할 때 유용하다.

var sb = new StringBuilder()
    .AppendFormat("{0} 클래스를 사용한 ", nameof(StringBuilder))
    .Append("메서드 ")
    .AppendLine("체이닝 ")
    .Append("안녕!")
    .ToString()
    .Trim();
Console.WriteLine(sb);
  • 결과

메서드에 서식을 주어 정수에 기호 표시하기

Console.WriteLine(10.ToString("+#;-#;0"));
Console.WriteLine(string.Format("{0:+#;-#;0}", -10));
Console.WriteLine($"{10:+#;-#;0}");
  • 결과

예외 처리하기

try~catch~finally 구문

try
{
    int now = DateTime.Now.Second;
    Console.WriteLine($"[0] 현재 {now} 초");
    int result = 2 / (now % 2);
    Console.WriteLine("[1] 홀수 초에서는 정상 처리");
}
catch (Exception ex) // 에러를 인수로 건네 받음.
{
    Console.WriteLine(ex.Message); // 에러를 출력
    Console.WriteLine("[2] 짝수 초에서는 런타임 에러 발생!");
}
finally
{
    Console.WriteLine("에러 발생과 상관없이 실행!");
}

try
{
    throw new Exception("내가 만든 에러"); // 무조건 에러를 발생시킴
}
catch (Exception e)
{
    Console.WriteLine(e.Message);
}
finally
{
    Console.WriteLine("try 구문을 종료합니다.");
}
  • 결과

컬렉션

컬렉션은 크기를 동적으로 변경할 수 있다.

Array

static void Main(string[] args)
{
    int[] arr = { 3, 1, 2, 4 };
    disp(arr);

    Array.Reverse(arr); // 순서 뒤집기
    disp(arr);

    Array.Sort(arr); // 정렬
    disp(arr);

    Array.Sort(arr, (a, b) => a > b ? -1 : 1); // 람다식을 이용한 역순 정렬
    disp(arr);

}
static void disp(int[] a)
{
    foreach(var item in a)
        Console.Write($"{item}  ");
    Console.WriteLine();
}
  • 결과

Stack

후입선출 (LIFO)

Stack stack = new Stack();
stack.Push("First");
stack.Push(2);

Console.WriteLine(stack.Peek()); // 맨 위데이터를 가져오고 삭제하지 않는다.
Console.WriteLine(stack.Pop()); // 맨 위 데이터를 가져오고 삭제한다.
Console.WriteLine(stack.Pop());

try
{
    stack.Pop(); // 스택 언더플로, 반대로 데이터가 너무 많으면 스택 오버플로
}
catch(Exception e)
{
    Console.WriteLine(e.Message);
}
  • 결과

Queue

선입선출(FIFO)

var queue = new Queue();
queue.Enqueue(10);
queue.Enqueue(20);

Console.WriteLine(queue.Peek());
Console.WriteLine(queue.Dequeue());
Console.WriteLine(queue.Dequeue());

try
{
    queue.Dequeue();
}
catch(Exception e)
{
    Console.WriteLine(e);
}
  • 결과

ArrayList

ArrayList list = new ArrayList();
list.Add("C#");
list.Add('C');
list.Add(3);
list.Remove('C');
list.RemoveAt(0);

Hashtable

Hashtable hash = new Hashtable();

hash[0] = "닷넷코리아";
hash["닉네임"] = "레드플러스";
hash["사이트"] = "비주얼아카데미";
Console.WriteLine(hash["닉네임"]);
  • 결과

위의 컬렉션들은 서로 다른 타입의 데이터를 저장이 가능하다. 하지만 데이터를 가져올 때 박싱, 언박싱이 발생하여 type-safe하지 못하여 제네릭을 사용하는 것이 낫다.

제네릭

Cup는 Cup of T로 읽는다.

generic은 특정 형식을 지정하여 컬렉션에 저장하고 사용할 수 있는 것으로 다른 데이터 형식을 추가할 수 없도록 형식 안정성이 적용되어 있다.

Stack

Stack<string> s = new Stack<string>();
s.Push("First");
s.Push("Second");

Console.WriteLine(s.Pop());
Console.WriteLine(s.Peek());
  • 결과

List

사용 빈도가 가장 크다

List<int> lstNum = new List<int>();
lstNum.Add(30);
lstNum.Add(40);
lstNum.RemoveAt(0);

Enumerable

Enumerable.Range(1, 10); // 1~10까지 정수 컬렉션 생성
Enumerable.Repeat(-1, 10); // -1을 10번 반복하는 정수 컬렉션 생성
string s = string.Join(", ", Enumerable.Range(0, 10));
Console.WriteLine(s);

var en = Enumerable.Range(1, 100) // 1부터 100까지 정수 중 짝수를 구하고
        .Where(i => i % 2 == 0)   // 짝수를 구하고
        .Reverse()                // 거꾸로 정렬한 후
        .Skip(10)                 // 10개를 제외하고
        .Take(5);                 // 5개를 가져온다.
foreach(var e in en)
{
    Console.WriteLine(e);
}
  • 결과

Enumerable 클래스의 Range와 Repeat 메서드 사용법

var numbers = Enumerable.Range(1, 5);
foreach (var n in numbers)
    Console.Write($"{n}\t");
Console.WriteLine();

var sameNumbers = Enumerable.Repeat(-1, 5);
foreach(var n in sameNumbers)
    Console.Write($"{n}\t");
Console.WriteLine();
  • 결과

Dictionary<T, T>

Add 메서드 또는 [ ] 인덱서를 통하여 데이터 추가가 가능하다.

키 값 중복은 오류를 발생시킨다.

IDictionary<string, string> data = new Dictionary<string, string>();
data.Add("cs", "C#");
data.Add("aspx", "ASP.NET");
data["cshtml"] = "ASP.NET MVC";
try
{
    data.Add("cs", "csharp");
}
catch(Exception e)
{
    Console.WriteLine(e.Message);
}
  • 결과

ContainsKey()와 TryGetValue() 메서드를 통해 안전하게 사용하는 것이 가능하다.

키와 밸류를 직접 추출하는 것도 가능하다.

IDictionary<string, string> data = new Dictionary<string, string>();

if (!data.ContainsKey("gg")) // "gg"라는 키가 존재하지 않는다면
{
    data["gg"] = "great goal";
}
if (data.TryGetValue("gg", out var result)) // "gg" 키의 값을 얻는 것을 시도
{
    Console.WriteLine(result);
}

// 키와 밸류를 직접 뽑을 수도 있다.
var key = data.Keys;
var value = data.Values;

Nullable

int?는 Nullable 형식의 줄임 표현이다.

null 병합 연산자 "??"를 사용하여 null 값을 검증할 수 있다.

Nullable<int> a = null;
int? b = 33;

Console.WriteLine(b.HasValue); // 필드
Console.WriteLine(b.Value); // 필드
Console.WriteLine(a.GetValueOrDefault()); // 메서드

string? s = null;
string message = s ?? "아무것도 없습니다."; // null 병합 연산자
Console.WriteLine(message);

int? x = null;
int y = x ?? default(int); // x가 null이면 디폴트값으로 초기화
Console.WriteLine($"{x}, {y}");

x ??= -1; // 복합 대입 연산자를 사용하여 null 값이라면 -1로 대체한다.
Console.WriteLine(x);
  • 결과

null 조건부 연산자 "?"와 null 병합 연산자

string message = null;
int? len = message?.Length; // null이면 null을 반환한다.
Console.WriteLine(len);

List<string> list;
list = null;
int num = list?.Count ?? 0; // null이면 0 반환
Console.WriteLine(num);
  • 결과

LINQ

LINQ (Language INtegrated Query)를 사용하여 확장 메서드 ( 특정 형식에 원래 없던 기능을 덧붙이는 기능)을 사용할 수 있다.

using System.Linq로 사용을 지시할 수 있다.

배열 확장 메서드

int[] n = { 1, 3, 4, 9, 9, 13};
int count = n.Count();
int sum = n.Sum();
double mean = n.Average();
int max = n.Max();
int min = n.Min();

Console.WriteLine($"n배열 요소의 개수: {count}");
Console.WriteLine($"n배열 요소의 합: {sum}");
Console.WriteLine($"n배열 요소의 평균: {mean}");
Console.WriteLine($"n배열 요소의 최대값: {max}");
Console.WriteLine($"n배열 요소의 최소값: {min}");
  • 결과

람다식

람다 식 = 화살표 함수 (arrow funtion): 매개변수로 전달된 이름이 없는 인라인 함수

⇒ = 람다 연산자 (lambda operator) = goes to = arrow = 이동

x ⇒ x+1은 'x는 x 플러스 1로 이동' 으로 읽을 수 있다.

Func<int, bool> isEven = x => x % 2 == 0;
Console.WriteLine(isEven(2));
Console.WriteLine(isEven(3));

Action<string> greet = name =>
{
    var message = $"Hello {name}";
    Console.WriteLine(message);
};
greet("You");
  • 결과

Where 메소드

where메소드의 반환형은 IEnumerable 이다.

int[] numbers = { 1, 2, 3, 4, 5 };
IEnumerable<int> newNumbers = numbers.Where(n => n > 3);
foreach (var item in newNumbers)
{
    Console.WriteLine(item);
}
  • 결과

IEnumerable 자료형을 List로 변환하기

int[] numbers = { 1, 2, 3, 4, 5 };
List<int> newNumbers = numbers.Where(n => n > 3).ToList();
foreach (var item in newNumbers)
{
    Console.WriteLine(item);
}
  • 결과

where 메서드로 조건 처리하기

var numbers = Enumerable.Range(1, 100);
List<int> newNumbers = numbers.Where(n => n % 2 == 1 && n % 3 == 0).ToList();
foreach(var el in newNumbers)
    Console.WriteLine(el);
Console.WriteLine($"배열 요소의 합계는 {newNumbers.Sum()}입니다.");
  • 결과

where 메서드를 사용하지 않고 조건 처리하기

var numbers = Enumerable.Range(1, 100);
int count = numbers.Count(x => x % 2 == 0 && x % 3 == 0);
Console.WriteLine($"배열 요소의 합계는 {count}입니다.");
  • 결과

All과 Any 확장 메서드

bool[] completes = { true, true, true };
Console.WriteLine($"전부 참값인가? {completes.All(x => x == true)}");
Console.WriteLine($"하나라도 false가 있나? {completes.Any(x => x == false)}");
  • 결과

Distinct() 확장 메서드로 중복 제거하기

int[] arr = { 1, 3, 3, 2, 9, 2, 00, 0, 29, 3, 9, 8, 2 };
var result = arr.Distinct();
foreach (var el in result)
    Console.WriteLine(el);
  • 결과

LINQ를 이용한 데이터 정렬과 검색

string[] colors = { "Red", "Green", "Blue" };
var sortedColors = colors.OrderBy(x => x);
var reverseSortedColors = colors.OrderByDescending(x => x);
foreach(var item in sortedColors)
    Console.WriteLine(item);
Console.WriteLine();
foreach(var item in reverseSortedColors)
    Console.WriteLine(item);
  • 결과

확장 메서드 체이닝

string[] colors = { "Red", "Green", "Blue" };
var sortedColors = colors.Where(x => x.Length > 3).OrderByDescending(x => x);
foreach(var item in sortedColors)
    Console.WriteLine(item);
  • 결과

Single 메서드로 조건과 일치하는 데이터 하나만 가져오기

First 메서드로 같은 동작을 할 수 있지만 First는 하나 이상의 데이터 중에서 첫번째 요소만 가져온다.

string[] colors = { "Red", "Green", "Blue" };
try
{
    string red = colors.Single(x => x == "red"); // 없는 데이터를 요청하면 오류 발생
}
catch(Exception e)
{
    Console.WriteLine(e);
}
string Red = colors.SingleOrDefault(x => x == "red");
Console.WriteLine(Red ?? "null");
  • 결과

zip 메서드: 두 개체 중 크기가 작은 것까지 원하는 형태로 병합하여 새로운 배열을 생성한다.

cf) SelectMany(), TakeWhile()

int[] numbers = { 1, 2, 3 };
string[] words = { "하나", "둘" };
var zipper = numbers.Zip(words, (first, second) => first + "-" + second);
foreach(var item in zipper)
    System.Console.WriteLine(item);

쿼리 구문

from, where, orderby, descending, select 키워드로 메서드 방식과 같이 구현할 수 있다.

var numbers = Enumerable.Range(1, 20);
numbers // 메소드 방식
    .Where(n => n % 2 == 0) // 짝수인 것만 고름
    .OrderByDescending(n => n) // 내림차순으로 정렬
    .Select(n => n * 2) // n을 모두 제곱함
    .ToList() // 리스트로 변경
    .ForEach(n => Console.WriteLine(n)); // foreach 메서드

var EvenQuery = from n in numbers // 쿼리 방식
           where n % 2 == 0 // 짝수인 것들을 골라서
           orderby n descending // 내림차순으로 정렬하여
           select n*2; // 제곱을 한다.
foreach (var item in EvenQuery)
    Console.WriteLine(item);
  • 결과

알고리즘

근삿값 알고리즘

int Abs(int n) => n < 0 ? -n : n; // 절대값을 구하는 람다식
int min = int.MaxValue;

int[] num = { 0b10101, 0x143, 0b11110, 0x1B, 0b10001 };
int target = 25; // 목표 근사치
int near = default; // 정답이 저장될 변수

for (int i = 0; i < num.Length; i++)
{
    int abs = Abs(num[i] - target);
    if(abs < min)
    {
        min = abs;
        near = num[i];
    }
}
System.Console.WriteLine($"{target}과 가장 근접한 값은 차이가 {min}만큼 나는 {near}입니다.");

순위 알고리즘

int[] scores = { 90, 33, 78, 99, 27, 100 };
int[] rank = Enumerable.Repeat(1, scores.Length).ToArray();

for (int i = 0; i < scores.Length; i++)
{
    for (int j = 0; j < scores.Length; j++)
    {
        if (scores[i] < scores[j])
        {
            rank[i]++;
        }
    }
}
for (int i = 0; i < scores.Length; i++){
    System.Console.WriteLine($"{scores[i], 3}점 - {rank[i]}등"); // 문자열 보간법에서 폭지정
}
  • 결과

클래스

  1. 클래스 생성 시 public 액세스 한정자를 생략하면 기본값인 internal을 갖는다.

    internal은 해당 프로그램 내에서 언제든지 접근이 가능하다.

  2. 클래스 이름은 대문자로 시작하는 명사를 사용한다.

    클래스 이름을 지을 때는 축약형, 접두사, 언더스코어같은 것은 사용하지 않는다.

  3. 클래스의 주요 구성 요소

    • 멤버: 클래스에 속하는 모든 것을 의미
    • 필드: 클래스 내에 선언된 변수
    • 메서드: 개체 동작이나 기능을 정의
    • 생성자: 개체 필드를 초기화
    • 소멸자: 개체를 모두 사용한 후 메모리에서 소멸될 때 실행된다.
    • 속성: 개체의 색상, 크기, 형태 등을 정의한다.
  4. 액세스 한정자: 클래스에 접근할 수 있는 범위를 결정한다.

기본적인 클래스, 인스턴스 메서드

static이 붙지 않은 메서드는 인스턴스 메서드이다.

인스턴스 메서드를 호출하려면 new 키워드를 사용하여 호출한다.

public class Counter
{
    public void GetTodayVisitCount()
    {
        System.Console.WriteLine("오늘 12명이 접속하였습니다.");
    }
}
static void Main(string[] args)
{
    Counter counter = new Counter();
    counter.GetTodayVisitCount();
}

클래스 익명 형식 (anonymous type)

익명 형식을 만들 때 각 데이터 형식은 자동으로 유추해서 만든다.

var choi = new { Name = "최호승", Age = 27 };
System.Console.WriteLine($"이름: {choi.Name}, 나이: {choi.Age}");

ToString() 메서드 오버라이드

class My { }
class Your
{
    public override string ToString()
    {
        return "새로운 문자로 지정";
    }
}
static void Main(string[] args)
{
    My my = new My();
    Your your = new Your();
    Console.WriteLine(my);
    Console.WriteLine(your);
}
  • 결과

using 지시문으로 네임스페이스 별명 만들기

using sc = System.Console;

class P
{
    static void Main(string[] args)
    {
        sc.WriteLine("my name");
    }
}

엑세스 한정자

  • public: 멤버에 대한 접근이 제한되지 않는다.
  • private: 현재 클래스 내에서만 접근이 가능하다.
  • protected: 현재 클래스와 파생 클래스에만 접근이 허가된다.
  • internal: 현재 프로젝트의 모든 클래스에서 접근이 허가된다.
  • protected internal: 현재 어셈블리(DLL파일) 또는 현재 어셈블리에서 파생된 모든 클래스에 액세스가 허가된다.

여러가지 형태의 필드 선언, 초기화

using System;

class P
{
    private string name = "최호승"; // 변수 필드이다.
    private const int age = 27; // 상수 필드이다.
    private readonly string nickname = "d2h10s"; // 읽기 전용 형식의 필드이다.
    private string[] social = { "instagram", "facebook" }; // 배열 필드이다.
    private object all = DateTime.Now.ToShortTimeString(); // 모든 형식의 필드이다.

    static void Main(string[] args)
    {
        
    }
}

생성자

생성자는 반환값을 가지지 않고 이름은 클래스 이름과 동일하다.

기본 생성자: 매개변수가 없는 생성자

static 생성자와 public 생성자로 구분된다.

using System;

class P
{
    class Dog
    {
        private string name;
        public Dog(string name)
        {
            this.name = name;
        }
        public string Cry()
        {
            return name + "가 멍멍!";
        }
    }
    static void Main(string[] args)
    {
        Dog dog = new Dog("바둑이");
        Console.WriteLine(dog.Cry());
    }
}
  • 결과

생성자 오버로드

using System;

class P
{
    class Dog
    {
        private string name;
        public Dog()
        {
            Console.WriteLine("기본 생성자 실행");
        }
        public Dog(string name)
        {
            this.name = name;
            Console.WriteLine("오버로드 된 생성자 실행");
        }
        public string Cry()
        {
            return name + "가 멍멍!";
        }
    }
    static void Main(string[] args)
    {
        Dog dog1 = new Dog("바둑이1");
        Dog dog2 = new Dog();
        Console.WriteLine(dog1.Cry());
    }
}
  • 결과

정적 생성자와 인스턴스 생성자

정적 생성자는 매개변수를 포함할 수 없다.

using System;

class P
{
    class Dog
    {
        private static readonly string _name;
        private string name;
        static Dog()
        {
            _name = "나비";
        }
        public Dog()
        {
            Console.WriteLine("기본 생성자 실행");
        }
        public Dog(string name)
        {
            this.name = name;
            Console.WriteLine("오버로드 된 생성자 실행");
        }
        public string Cry()
        {
            return name + "가 멍멍!";
        }
        public static void Show()
        {
            Console.WriteLine(_name+"입니다.");
        }
    }
    static void Main(string[] args)
    {
        Dog.Show();
        Dog dog = new Dog("바둑이");
        Console.WriteLine(dog.Cry());
    }
}
  • 결과

생성자에서 this()는 자신의 또 다른 생성자를 의미한다.

using System;

class P
{
    private string message = "[1] 안녕하세요";
    public P() => Console.WriteLine(this.message); // 기본생성자
    public P(string message) : this()
    {
        this.message = message;
        Console.WriteLine(this.message);
    }

    static void Main(string[] args)
    {
        new P("[2] 잘가요"); // 매개변수 생성자 이전에 기본 생성자를 먼저 호출한다.
    }
}
  • 결과

this() 생성자를 통하여 생성자 포워딩 하기

using System;

class P
{
    public P() : this(1000) { }
    public P(int money) => Console.WriteLine("Money : {0:#,###}", money); // 식 본문 생성자
    static void Main(string[] args)
    {
        var basic = new P();
        var bonus = new P(2000);
    }
}
  • 결과

소멸자

Garbage Collector에서 클래스의 인스턴스를 제거할 때 가장 마지막에 호출되는 메서드이다.

닷넷 프레임워크 기반으로 콘솔을 만들면 프로그램이 종료될 때 소멸자를 실행하고

닷넷 코어 기반으로 콘솔을 만들면 프로그램이 종료된 후 소멸자를 실행한다.

class Car
{
	~Car()
	{
		// 개체가 소멸될 때 필요한 기능 수행
	}
}

매개변수

참조형 매개변수와 반환형 매개변수

using System;

class P
{
    static void Main(string[] args)
    {
        int num = 10;
        Console.WriteLine($"[1] {num}");
        Do(num);
        Console.WriteLine($"[2] {num}");
        DoRef(ref num);
        Console.WriteLine($"[3] {num}");
        DoOut(out num);
        Console.WriteLine($"[4] {num}");
    }
    static void Do(int num)
    {
        num = 20;
    }
    static void DoRef(ref int num) // 참조형 매개변수 전달방식
    {
        num = 30;
    }
    static void DoOut(out int num) // 반환명 매개변수 전달방식
    {
        num = 40;
    }

}
  • 결과

가변 길이 매개변수

using System;

class P
{
    static void Main(string[] args)
    {
        Console.WriteLine(sumAll(3,5,8));
        Console.WriteLine(sumAll(2,7));
    }
    static int sumAll(params int[] numbers)
    {
        int sum = 0;
        foreach (var num in numbers)
        {
            sum += num;
        }
        return sum;
    }
}
  • 결과

선택적 매개변수(optional parameter, default argument)와 명명된 매개변수 (named parameter, named argumet)

using System;

class P
{
    static void Main(string[] args)
    {
        Console.WriteLine(Add(a:3)); // 명명된 매개변수
    }
    static int Add(int a, int b = 1) => a + b; // 선택적 매개변수
}

속성 (Property)

속성은 개체 필드 중 일부를 외부에 공개할 때 사용하는 방법이다.

private 성격이 있는 필드를 public 속성으로 외부에 공개할 때 유용하다.

기본형식: 아래와 같이 한 줄로 속성을 정의하는 것을 자동 속성(auto property)라고 한다.

class 클래스이름
{
	[반환형식] 속성이름 { get; set; }
}
class Car
{
    public string Name { get; set; }
}
static void Main(string[] args)
{
    Car car = new Car();
    car.Name = "my Car";
    Console.WriteLine(car.Name);
}

접근자와 전체 속성

setter: 속성에 값을 설정하는 것

getter: 값을 읽어오는 것

class Car
{
    private string name;
    public string Name
    {
        get { return name; }
        set { name = value; }
    }
}
static void Main(string[] args)
{
    Car car = new Car();
    car.Name = "my Car";
    Console.WriteLine(car.Name);
}

식 본문 속성 사용하기

class Car
{
    private string name;
    public string Name
    {
        get => name;
        set => name = value;
    }
}
static void Main(string[] args)
{
    Car car = new Car();
    car.Name = "my Car";
    Console.WriteLine(car.Name);
}

자동 속성 이니셜라이저 (auto property initializers): 속성을 선언과 동시에 기본값으로 초기화할 수 있다.

class Car
{
    private string name;
    public string Name { get; set; } = "부릉이"; // 자동 속성 이니셜라이저
}
static void Main(string[] args)
{
    Car car = new Car();
    Console.WriteLine(car.Name);
}

읽기 전용 속성 혹은 쓰기 전용 속성

class Car
{
    public string Name { get;} = "부릉이"; // 읽기 전용 속성
    public int Age { get;  private set; } = 33; // 쓰기 전용 속성
}
static void Main(string[] args)
{
    Car car = new Car();
    Console.WriteLine(car.Name);
}

개체 이니셜라이저 (object initializer)

class Car
{
    public string Name { get; set; }
    public int Age { get; set; }
}
static void Main(string[] args)
{
    Car car = new Car { Name = "부릉이", Age = 33 }; // 개체 이니셜라이저
    Console.WriteLine(car.Name);
}

자동 속성을 사용하여 레코드 클래스 구현하기

레코드: 표 형태의 데이터

모델 클래스: 속성을 사용하여 레코드 형태로 데이터를 관리하는 클래스

public class Customer
{
    public int Id { get; set; }
    public string Name { get; set; }
    public string City { get; set; }
}
static void Main(string[] args)
{
    var customer = new Customer { Id = 1, Name = "박용준", City = "인천" };
    Console.WriteLine($"{customer.Id}, {customer.Name}, {customer.City}");
}

nameof 연산자로 속성, 메서드의 이름 자체를 문자열로 가져오기

public class Customer
    {
        public int Id { get; set; }
        public string Name { get; set; }
        public string City { get; set; }
    }
    static void Main(string[] args)
    {
        var customer = new Customer();
        Console.WriteLine(nameof(customer.City));
    }
  • 결과

익명 형식을 사용하면 간단하게 개체를 생성할 수 있다.

static void Main(string[] args)
{
    var person = new { Name = "백승수", Age = 26 };
		person = new {Name = "최호승", Age = 16}; // 형식이 똑같다면 다른 익명형식을 대입할 수 있다.
    Console.WriteLine(person.Name);
}

인덱서

정수형 인덱서 만들기

class Catalog
{
    public string this[int index]
    {
        get
        {
            return (index % 2 == 0) ? $"{index}: 짝수반환" : $"{index}: 홀수반환";
        }
    }
}
static void Main(string[] args)
{
    Catalog catalog = new Catalog();
    System.Console.WriteLine(catalog[0]);
    System.Console.WriteLine(catalog[1]);
    System.Console.WriteLine(catalog[2]);
}
  • 결과

인덱서를 사용하여 배열 형식의 필드에 접근하기

public class Car
{
    private string[] names;

    public Car(int length) { names = new string[length]; }
    public int Length { get { return names.Length; } }
    public string this[int index]
    {
        get { return names[index]; }
        set { names[index] = value; }
    }

}
static void Main(string[] args)
{
    Car car = new Car(3);
    car[0] = "CLA";
    car[1] = "CLS";
    car[2] = "AMG";
    for (int i = 0; i < car.Length; i++)
    {
        System.Console.WriteLine($"{car[i]}");
    }
}
  • 결과

반복기

yield return 구문은 IEnumerable 인터페이스 형식으로 반환된다.

static IEnumerable MultiData()
{
    yield return "Hello";
    yield return "World";
    yield return "C#";
}

static void Main(string[] args)
{
    foreach (var item in MultiData())
    {
        System.Console.WriteLine(item);
    }
}
  • 결과

IEnumerable로 컬렉션 형태의 데이터 받기

static IEnumerable<int> Greater(int[] numbers, int greater)
{
    List<int> temp = new List<int>();
    foreach (var n in numbers)
    {
        if (n > greater) temp.Add(n);
    }
    return temp;
}

static void Main(string[] args)
{
    int[] numbers = { 1, 2, 3, 4, 5 };
    foreach (var item in Greater(numbers, 3))
    {
        System.Console.WriteLine(item);
    }
}
  • 결과

GetEnumerator()와 MoveNext(), Current 메소드

static IEnumerable<int> Generator()
{
    yield return 1;
    yield return 3;
    yield return 5;
}

static void Main(string[] args)
{
    var nums = Generator().GetEnumerator();
    nums.MoveNext();
    System.Console.WriteLine(nums.Current);
}
  • 결과

대리자

대리자(함수 포인터)는 delegate 키워드를 사용하여 만든다. 함수 자체를 데이터 하나로 보고 다른 메서드를 대신 실행하는 기능으로 한 번에 메서드 하나 이상을 대신해서 호출할 수 있는 개념이다.

  • 메서드의 매개변수로 대리자 변수를 넘길 수 있다. 대리자를 사용하여 함수의 매개변수로 함수 자체를 전달할 수 있다.
  • 서드의 매개변수로 또 다른 메서드 호출을 넘기는 기능이다.
  • 자는 동일한 메서드 시그니처를 갖는 메서드 참조를 담을 수 있는 그릇 역할을 한다.
  • 대리자는 람다와 개념이 같다.
  • 대리자를 사용하면 함수를 모아 놓았다 나중에 실행하거나 실행을 취소할 수 있다.
  • 대리자는 내부적으로 MulticastDelegate 클래스에서 기능을 상속한다.
  • 대리자는 이벤트를 만들어 내는 중간 단계의 키워드로 존재한다.

기본적인 델리게이트 사용법

static void Hi() => System.Console.WriteLine("안녕하세요");
delegate void SayDelegate();
static void Main(string[] args)
{
    SayDelegate say = Hi;
    say();

    var hi = new SayDelegate(Hi);
    hi();
}
profile
Hi, my name is Eugene CHOI the Automotive MCU FW developer.

0개의 댓글