본문 바로가기
TIL

11.14 (TIL)

by 오랑이귀엽다 2023. 11. 14.

Console.ForegroundColor

콘솔 텍스트 색을 변경

 

간단 예시

더보기

using System;

class Program
{
    static void Main()
    {
        Console.ForegroundColor = ConsoleColor.Red;
        Console.WriteLine("This is red text");
        
        // 원래 색상으로 돌아가기
        Console.ResetColor();

        Console.WriteLine("This is the default color");

        // 프로그램 종료 전에 콘솔 창 열려있도록 하기 위해 대기
        Console.ReadLine();
    }
}

위의 코드에서 Console.ForegroundColor 속성을 사용하여 텍스트 색상을 변경하고,

Console.ResetColor()를 호출하여 원래의 기본 색상으로 돌아간다

이렇게 하면 특정 부분에 대해 색상을 변경하고 원래 색상으로 복원할 수 있다.

 

 

Console.ReadKey();

콘솔 애플리케이션에서 사용자의 키보드 입력을 대기하고, 사용자가 키를 누를 때까지 대기하는 메서드

주로 콘솔 애플리케이션에서 프로그램의 종료를 지연시키거나, 특정 키 입력을 대기하는 데 사용

 

간단 예시

더보기

using System;

class Program
{
    static void Main()
    {
        Console.WriteLine("Press any key to continue...");
        
        // 사용자의 키 입력을 대기
        Console.ReadKey();

        Console.WriteLine("You pressed a key. Program exiting...");
    }
}

 

인터페이스 ( Interface )

1) 사용하는 이유

1. 코드의 재사용성 : 

인터페이스를 사용하면 다른 클래스에서 해당 인터페이스를 구현하여 동일한 기능을 공유할 수 있다.

인터페이스를 통해 다양한 클래스가 동일한 동작을 수행할 수 있으므로 코드의 재사용성이 향상

2. 다중 상속 제공 : 

C#에서는 클래스는 단일 상속만을 지원하지만, 인터페이스는 다중 상속을 지원

클래스가 여러 인터페이스를 구현함으로써 여러 개의 기능을 조합할 수 있다.

다중 상속을 통해 클래스는 더 다양한 동작을 수행할 수 있다.

3. 유연한 설계 :

인터페이스를 사용하면 클래스와 인터페이스 간에 느슨한 결합을 형성

클래스는 인터페이스를 구현하기만 하면 되므로,

클래스의 내부 구현에 대한 변경 없이 인터페이스의 동작을 변경하거나 새로운 인터페이스를 추가할 수 있다.

유연하고 확장 가능한 소프트웨어 설계를 가능

 

2) 인터페이스 특징

인터페이스란 클래스가 구현해야 하는 멤버들을 정의

인터페이스는 클래스의 일종이 아니며, 클래스에 대한 제약 조건을 명시

클래스가 인터페이스를 구현할 경우, 모든 인터페이스 멤버를 구현 해야함

인터페이스는 다중 상속을 지원

 

구현 간단예시

더보기

using System;

// 예시 인터페이스 정의
public interface IDrawable
{
    void Draw(); // 모든 구현 클래스는 이 메서드를 구현해야함
}

// 구현 클래스
public class Circle : IDrawable
{
    private int radius;

    public Circle(int radius)
    {
        this.radius = radius;
    }

    // IDrawable 인터페이스의 메서드 구현
    public void Draw()
    {
        Console.WriteLine($"Drawing a circle with radius {radius}");
    }
}

public class Square : IDrawable
{
    private int sideLength;

    public Square(int sideLength)
    {
        this.sideLength = sideLength;
    }

    // IDrawable 인터페이스의 메서드 구현
    public void Draw()
    {
        Console.WriteLine($"Drawing a square with side length {sideLength}");
    }
}

class Program
{
    static void Main()
    {
        // 인터페이스를 사용하여 다양한 도형 그림.
        IDrawable circle = new Circle(5);
        IDrawable square = new Square(4);

        DrawShape(circle);
        DrawShape(square);
    }

    // IDrawable을 인자로 받아 Draw 메서드를 호출하는 메서드
    static void DrawShape(IDrawable shape)
    {
        shape.Draw();
    }
}

 

// IDrawable 인터페이스는 Draw 메서드를 선언

// CircleSquare 클래스는 각각 이 인터페이스를 구현

// DrawShape 메서드는 IDrawable을 인자로 받아서 해당 도형을 그리는데 사용

다중 상속 구현 간단 예시

더보기

// 인터페이스 1: IItemPickable
public interface IItemPickable
{
    void PickUp(); // 아이템을 주웠을 때 실행될 메서드를 선언한 인터페이스
}

// 인터페이스 2: IDroppable
public interface IDroppable
{
    void Drop(); // 아이템을 버렸을 때 실행될 메서드를 선언한 인터페이스
}

// 아이템 클래스: Item 클래스는 IItemPickable과 IDroppable 인터페이스를 모두 구현
public class Item : IItemPickable, IDroppable
{
    public string Name { get; set; }

    public void PickUp()
    {
        Console.WriteLine("아이템 {0}을 주웠습니다.", Name);
    }

    public void Drop()
    {
        Console.WriteLine("아이템 {0}을 버렸습니다.", Name);
    }
}

// 플레이어 클래스: 아이템과 상호작용하는 플레이어를 나타내는 클래스
public class Player
{
    // 아이템을 주워서 PickUp 메서드 실행
    public void InteractWithItem(IItemPickable item)
    {
        item.PickUp();
    }

    // 아이템을 버려서 Drop 메서드 실행
    public void DropItem(IDroppable item)
    {
        item.Drop();
    }
}

// 게임 실행: 메인 메서드에서 플레이어가 아이템을 주우고 버리는 상황을 시뮬레이션
static void Main()
{
    Player player = new Player();
    Item item = new Item { Name = "Sword" };

    // 아이템 주울 수 있음
    player.InteractWithItem(item);

    // 아이템 버릴 수 있음
    player.DropItem(item);
}

 

 

 

3) 인터페이스 vs 추상클래스

인터페이스의 특징과 장단점:

인터페이스는 추상적인 동작만 정의하고, 구현을 갖지 않는다.

다중 상속이 가능하며, 여러 클래스가 동일한 인터페이스를 구현할 수 있다.

클래스들 간의 결합도를 낮추고, 유연한 상호작용을 가능하게 함

코드의 재사용성과 확장성을 향상

단점으로는 인터페이스를 구현하는 클래스가 모든 동작을 구현해야 한다는 것 때문에 작업량이 증가할 수 있다.

 

추상 클래스의 특징과 장단점:

추상 클래스는 일부 동작의 구현을 가지며, 추상 메서드를 포함할수 있다

단일 상속만 가능하며, 다른 클래스와 함께 상속 계층 구조를 형성할 수 있다.

공통된 동작을 추상화하여 코드의 중복을 방지하고, 확장성을 제공

구현된 동작을 가지고 있기 때문에, 하위 클래스에서 재정의하지 않아도 될 경우 유용

단점으로는 다중 상속이 불가능하고,

상속을 통해 밀접하게 결합된 클래스들을 형성하므로 유연성이 제한될 수 있다.

 

열거형 (Enums)

1) 사용하는 이유

가독성:

열거형을 사용하면 일련의 연관된 상수들을 명명할 수 있다.

코드의 가독성이 향상되고, 상수를 사용할 때 실수로 잘못된 값을 할당하는 것을 방지

 

자기 문서화(Self-documenting):

열거형은 의미 있는 이름을 사용하여 상수를 명명할 수 있다.

코드의 가독성이 향상되며, 상수의 의미를 명확하게 설명할 수 있다.

 

스위치 문과의 호환성:

열거형은 스위치 문과 함께 사용될 때 유용

열거형을 사용하면 스위치 문에서 다양한 상수 값에 대한 분기를 쉽게 작성할 수 있다.

 

2) 열거형 특징

열거형은 서로 관련된 상수들의 집합을 정의할 때 사용

열거형의 각 상수는 정수 값으로 지정

 

구현 예시

더보기

using System;

public class Program
{
    // 열거형 정의
    public enum Days
    {
        Sunday,    // 0
        Monday,    // 1
        Tuesday,   // 2
        Wednesday, // 3
        Thursday,  // 4
        Friday,    // 5
        Saturday   // 6
    }

    public static void Main()
    {
        // 열거형 변수 선언 및 초기화
        Days today = Days.Wednesday;

        // 열거형 값 출력
        Console.WriteLine("Today is: " + today);

        // switch 문을 사용한 열거형 값에 따른 동작
        switch (today)
        {
            case Days.Monday:
                Console.WriteLine("It's the beginning of the week.");
                break;
            case Days.Wednesday:
                Console.WriteLine("It's the middle of the week.");
                break;
            case Days.Friday:
                Console.WriteLine("It's almost the weekend!");
                break;
            default:
                Console.WriteLine("It's a regular day.");
                break;
        }
    }
}

// Days라는 열거형을 정의하고, 그 중 하나인 today 변수를 선언하고 초기화

// 그런 다음 switch 문을 사용하여 today의 값에 따라 다른 동작을 수행

 

 

 

예외 처리

1) 예외란?

예외는 프로그램 실행 중에 발생하는 예기치 않은 상황을 의미

예외는 프로그램의 정상적인 흐름을 방해하고 오류를 야기할 수 있다.

 

2) 예외 처리의 필요성과 장점

예외 처리는 예외 상황에 대비하여 프로그램을 안정적으로 유지하는 데 도움을 줌

예외 처리를 통해 오류 상황을 적절히 처리하고, 프로그램의 실행을 계속할 수 있다.

예외 처리는 프로그램의 안정성을 높이고 디버깅을 용이하게 함

 

3) 예외 처리 구현

C#에서는 try-catch 블록을 사용하여 예외 처리를 수행

try 블록 내에서 예외가 발생할 수 있는 코드를 작성하고, catch 블록에서 예외를 처리함

 

간단 예시

더보기

try
{
    // 예외가 발생할 수 있는 코드
}
catch (ExceptionType1 ex)
{
    // ExceptionType1에 해당하는 예외 처리
}
catch (ExceptionType2 ex)
{
    // ExceptionType2에 해당하는 예외 처리
}
finally
{
    // 예외 발생 여부와 상관없이 항상 실행되는 코드
}

간단 구현

더보기

using System;

class program
{
    static void Main()
    {
        // 사용자로부터 숫자를 입력받음
        Console.Write("숫자를 입력하세요: ");
        string userInput = Console.ReadLine();

        try
        {
            // 입력받은 문자열을 숫자로 변환
            int number = int.Parse(userInput);

            // 숫자를 10으로 나누어 출력
            int result = 10 / number;

            // 결과 출력
            Console.WriteLine("결과: " + result);
        }
        catch (FormatException ex)
        {
            // 숫자로 변환하는 과정에서 발생한 예외를 처리
            Console.WriteLine("올바른 숫자 형식이 아닙니다. 다시 시도하세요.");
            Console.WriteLine("에러 메시지: " + ex.Message);
        }
        catch (DivideByZeroException ex)
        {
            // 0으로 나누는 예외를 처리
            Console.WriteLine("0으로 나눌 수 없습니다.");
            Console.WriteLine("에러 메시지: " + ex.Message);
        }
        catch (Exception ex)
        {
            // 기타 예외를 처리
            Console.WriteLine("오류가 발생했습니다.");
            Console.WriteLine("에러 메시지: " + ex.Message);
        }
    }
}

// try 블록 내에서 사용자로부터 입력받은 문자열을 숫자로 변환하고, 그 숫자로 10을 나누어 결과를 출력하려고 시도

// catch 블록에서는 여러 종류의 예외를 처리하고 각각에 대한 메시지를 출력

// 프로그램이 예외를 처리하고 사용자에게 적절한 메시지를 표시할 수 있다.

 

 

4) catch 블록의 우선순위

catch 블록은 위에서부터 순서대로 실행되며, 예외 타입에 해당하는 첫 번째 catch 블록이 실행

예외 타입은 상속 관계에 있는 경우 상위 예외 타입의 catch 블록이 먼저 실행

 

5) 다중 catch 블록

여러 개의 catch 블록을 사용하여 다양한 예외 타입을 처리할 수 있다.

다중 catch 블록을 사용하면 각각의 예외 타입에 따라 다른 예외 처리 코드를 작성할 수 있다.

 

6) 예외 객체

catch 블록에서는 예외 객체를 사용하여 예외에 대한 정보를 액세스할 수 있다.

예외 객체를 사용하여 예외의 타입, 메시지 등을 확인하고 처리할 수 있다.

 

 

finally 블록

1) finally 블록의 역할과 사용법

finally 블록은 예외 발생 여부와 상관없이 항상 실행되는 코드 블록

finally 블록은 예외 처리의 마지막 단계로, 예외 발생 시 정리 작업이나 리소스 해제 등의 코드를 포함할 수 있다.

finally 블록은 try-catch 블록 뒤에 작성되며, 생략할 수도 있다.

 

2) finally 블록의 실행 시점

예외가 발생한 경우: 예외가 발생하면 예외 처리 과정을 거친 후 finally 블록이 실행

예외가 발생하지 않은 경우: 예외가 발생하지 않아도 finally 블록은 정상적으로 실행

 

간단 구현

더보기

using System;

class ExceptionHandlingExample
{
    static void Main()
    {
        // 사용자로부터 숫자를 입력받음
        Console.Write("숫자를 입력하세요: ");
        string userInput = Console.ReadLine();

        try
        {
            // 입력받은 문자열을 숫자로 변환
            int number = int.Parse(userInput);

            // 숫자를 10으로 나누어 출력
            int result = 10 / number;

            // 결과 출력
            Console.WriteLine("결과: " + result);
        }
        catch (FormatException ex)
        {
            // 숫자로 변환하는 과정에서 발생한 예외를 처리
            Console.WriteLine("올바른 숫자 형식이 아닙니다. 다시 시도하세요.");
            Console.WriteLine("에러 메시지: " + ex.Message);
        }
        catch (DivideByZeroException ex)
        {
            // 0으로 나누는 예외를 처리
            Console.WriteLine("0으로 나눌 수 없습니다.");
            Console.WriteLine("에러 메시지: " + ex.Message);
        }
        catch (Exception ex)
        {
            // 기타 예외를 처리
            Console.WriteLine("오류가 발생했습니다.");
            Console.WriteLine("에러 메시지: " + ex.Message);
        }
        finally
        {
            // finally 블록은 예외 발생 여부에 상관없이 항상 실행됨
            Console.WriteLine("프로그램이 종료되었습니다.");
        }
    }
}

// 사용자로부터 입력받은 문자열을 숫자로 변환하고, 그 숫자로 10을 나누어 결과를 출력하는 프로그램

// 예외가 발생할 수 있는 부분을 try, catch, finally 블록을 사용하여 처리

// finally 블록은 예외 발생 여부에 상관없이 항상 실행되는 부분

 

 

사용자 정의 예외

1) 사용자 정의 예외 클래스 작성

사용자는 필요에 따라 자신만의 예외 클래스를 작성할 수 있다.

사용자 정의 예외 클래스는 Exception 클래스를 상속받아 작성하며, 추가적인 기능이나 정보를 제공할 수 있다.

 

2) 사용자 정의 예외 처리

사용자 정의 예외가 발생한 경우, try-catch 블록에서 해당 예외를 처리할 수 있다.

catch 블록에서 사용자 정의 예외 타입을 명시하여 예외를 처리하고, 예외에 대한 적절한 처리 로직을 작성할 수 있다.

 

간단 예시

더보기

using System;

// 사용자 정의 예외 클래스
public class CustomException : Exception
{
    // 사용자 정의 예외 클래스에 필요한 추가 속성이나 메서드를 정의할 수 있다.
    public CustomException(string message) : base(message)
    {
        // 생성자에서 기본 예외 클래스의 생성자를 호출하여 메시지를 설정
    }
}

class CustomExceptionExample
{
    static void Main()
    {
        try
        {
            // 사용자 정의 예외를 발생시키는 메서드 호출
            ThrowCustomException();
        }
        catch (CustomException ex)
        {
            // 사용자 정의 예외를 처리
            Console.WriteLine("사용자 정의 예외가 발생했습니다.");
            Console.WriteLine("에러 메시지: " + ex.Message);
        }
        catch (Exception ex)
        {
            // 기타 예외를 처리
            Console.WriteLine("오류가 발생했습니다.");
            Console.WriteLine("에러 메시지: " + ex.Message);
        }
    }

    // 사용자 정의 예외를 발생시키는 메서드
    static void ThrowCustomException()
    {
        // 어떤 조건에 따라서 사용자 정의 예외를 발생시킬 수 있습니다.
        bool condition = true;

        if (condition)
        {
            // 사용자 정의 예외를 발생시킴
            throw new CustomException("이것은 사용자 정의 예외입니다.");
        }
        else
        {
            // 다른 예외를 발생시킬 수도 있음
            throw new Exception("다른 예외가 발생했습니다.");
        }
    }
}

// CustomExceptionException 클래스를 상속받아 사용자가 정의한 예외 클래스

// ThrowCustomException 메서드에서 특정 조건에 따라 이 예외를 발생시키고, Main 메서드에서는 이를 처리하는 방법을 보여줌

// 특정한 상황에 사용자가 정의한 예외를 사용하여 프로그램 흐름을 제어할 수 있다.

 

값형과 참조형

1) 값형(Value Type)

값형은 변수에 값을 직접 저장

변수가 실제 데이터를 보유하고 있으며, 해당 변수를 다른 변수에 할당하거나 전달할 때는 값이 복사

값형 변수의 수정은 해당 변수의 값만 변경하므로 다른 변수에 영향을 주지 않는다.

int, float, double, bool 등의 기본 데이터 타입들이 값형에 해당

 

간단 구현

더보기

using System;

class ValueTypeExample
{
    static void Main()
    {
        // 정수형 값형 예시: int
        int integerValue = 42;
        Console.WriteLine("정수형 값: " + integerValue);

        // 부동 소수점 값형 예시: double
        double doubleValue = 3.14;
        Console.WriteLine("부동 소수점 값: " + doubleValue);

        // 문자 값형 예시: char
        char charValue = 'A';
        Console.WriteLine("문자 값: " + charValue);

        // 사용자 정의 값형 예시
        // 사용자 정의 값형은 struct를 사용하여 정의됩니다.
        // 여기서는 Point라는 간단한 2D 포인트를 나타내는 값형을 정의.
        Point pointValue = new Point(10, 20);
        Console.WriteLine("사용자 정의 값형: (" + pointValue.X + ", " + pointValue.Y + ")");
    }
}

// 사용자 정의 값형(Point) 정의
public struct Point
{
    // 사용자 정의 값형에는 필드, 속성, 메서드 등이 포함될 수 있다.
    public int X { get; }
    public int Y { get; }

    // 생성자를 사용하여 값형을 초기화
    public Point(int x, int y)
    {
        X = x;
        Y = y;
    }
}

// 정수형(int), 부동 소수점(double), 문자(char)와 같은 내장 값형을 보여주고,

// 사용자 정의 값형을 나타내는 Point 구조체를 정의하여 사용

// 값형은 스택에 직접 저장되므로 속도 면에서 일반적으로 참조형보다 빠름

 

 

2) 참조형(Reference Type)

참조형은 변수가 데이터에 대한 참조(메모리 주소)를 저장

변수가 실제 데이터를 가리키는 참조를 갖고 있으며, 해당 변수를 다른 변수에 할당하거나 전달할 때는 참조가 복사

참조형 변수의 수정은 동일한 데이터를 가리키고 있는 다른 변수에 영향을 줄 수 있다.

클래스, 배열, 인터페이스 등이 참조형에 해당

 

간단 예시

더보기

using System;

class ReferenceTypeExample
{
    static void Main()
    {
        // 문자열 참조형 예시: string
        string stringValue = "Hello, Reference Type!";
        Console.WriteLine("문자열 값: " + stringValue);

        // 배열 참조형 예시: int 배열
        int[] intArray = { 1, 2, 3, 4, 5 };
        Console.Write("정수 배열 값: ");
        foreach (int num in intArray)
        {
            Console.Write(num + " ");
        }
        Console.WriteLine();

        // 클래스 참조형 예시
        // 여기서는 간단한 Person 클래스를 정의하여 사용합니다.
        Person personObject = new Person("John", 25);
        Console.WriteLine("사람의 이름: " + personObject.Name + ", 나이: " + personObject.Age);
    }
}

// 사용자 정의 클래스(Person) 정의
public class Person
{
    // 클래스에는 필드, 속성, 메서드 등이 포함될 수 있습니다.
    public string Name { get; set; }
    public int Age { get; set; }

    // 생성자를 사용하여 클래스를 초기화합니다.
    public Person(string name, int age)
    {
        Name = name;
        Age = age;
    }
}

// 문자열(string), 배열(int[]), 그리고 사용자 정의 클래스(Person)와 같은 참조형을 보여줌

// 참조형은 힙 메모리에 데이터를 저장하고, 스택에는 해당 데이터에 대한 참조(주소)를 저장

// 참조형은 데이터를 복사하는 대신에 데이터에 대한 참조를 전달하므로, 메모리 효율성과 데이터 공유가 가능

 

 

3) 값형과 참조형의 차이점

값형은 실제 데이터를 변수에 저장하고, 참조형은 데이터에 대한 참조를 변수에 저장

값형은 변수 간의 값 복사가 이루어지고, 참조형은 변수 간의 참조 복사가 이루어진다.

값형은 변수가 독립적으로 데이터를 가지며, 참조형은 변수가 동일한 데이터를 참조

 

박싱과 언박싱

1) 박싱(Boxing)

박싱은 값형을 참조형으로 변환하는 과정

값형 변수의 값을 메모리의 힙 영역에 할당된 객체로 래핑

박싱을 통해 값형이 참조형의 특징을 갖게 되며, 참조형 변수로 다뤄질 수 있다.

박싱된 값형은 참조로 전달되므로 메모리 오버헤드가 발생할 수 있다.

 

2) 언박싱(Unboxing)

언박싱은 박싱된 객체를 다시 값형으로 변환하는 과정

박싱된 객체에서 값을 추출하여 값형 변수에 할당

언박싱은 명시적으로 타입 캐스팅을 해야 하며, 런타임에서 타입 검사가 이루어진다.

잘못된 형식으로 언박싱하면 런타임 에러가 발생할 수 있다.

 

3) 박싱과 언박싱의 주요 특징

박싱과 언박싱은 값형과 참조형 사이의 변환 작업이므로 성능에 영향을 미칠 수 있다.

반복적인 박싱과 언박싱은 성능 저하를 초래할 수 있으므로 주의

 

박싱된 객체는 힙 영역에 할당되므로 가비지 컬렉션의 대상이 될 수 있다.

따라서 메모리 관리에 유의

 

박싱된 객체와 원래의 값형은 서로 독립적이므로 값을 수정하더라도 상호간에 영향을 주지 않는다.

 

간단 예시

object는 .NET Common Type System (CTS)의 일부이며, 모든 클래스의 직간접적인 상위 클래스

모든 클래스는 object에서 상속되며, object는 모든 형식을 참조할 수 있는 포괄적인 타입

더보기

using System;
using System.Collections.Generic;

class BoxingUnboxingExample
{
    static void Main()
    {
        // 박싱과 언박싱 예시

        // 값형을 참조형으로 박싱
        int intValue = 42;
        object boxedValue = intValue;

        // 참조형을 값형으로 언박싱
        int unboxedValue = (int)boxedValue;

        Console.WriteLine("박싱된 값: " + boxedValue);
        Console.WriteLine("언박싱된 값: " + unboxedValue);

        // 리스트를 활용한 박싱/언박싱 예시

        // int 값을 가지는 리스트 생성
        List<int> intList = new List<int>();
        intList.Add(10);
        intList.Add(20);
        intList.Add(30);

        // 리스트에 값을 박싱하여 저장
        List<object> objectList = new List<object>();
        foreach (int item in intList)
        {
            objectList.Add(item); // 박싱
        }

        // 리스트에서 값을 언박싱하여 가져와 사용
        foreach (object item in objectList)
        {
            int unboxedItem = (int)item; // 언박싱
            Console.WriteLine("언박싱된 값: " + unboxedItem);
        }
    }
}

// 이러한 변환은 성능 상의 오버헤드를 초래할 수 있으므로 사용 시 주의

// 박싱과 언박싱의 기본 개념을 보여주고 있다.

// 리스트를 활용하여 값형을 박싱하여 저장하고, 다시 언박싱하여 사용

// List<int>List<object>를 사용하여 박싱과 언박싱이 어떻게 이루어지는지를 확인할 수 있다.

'TIL' 카테고리의 다른 글

11.16 (TIL)  (0) 2023.11.16
11.15 (TIL)  (0) 2023.11.15
11.13 (TIL)  (0) 2023.11.13
11.10 (TIL)  (0) 2023.11.10
11.09 (TIL)  (0) 2023.11.09