C#문법 - 3

이준호·2023년 11월 8일
0

C#문법 종합반 3주차



📌 클래스와 객체

01. 객체지향 프로그래밍(Object-Oriented Programming, OOP)의 특징

1) 특징

1. 캡슐화(Encapsulation)

  • 관련된 데이터와 기능을 하나의 단위로 묶는 것을 의미한다.

  • 클래스를 사용하여 데이터와 해당 데이터를 조작하는 메서드를 함께 캡슐화하여 정보를 은닉하고, 외부에서 직접적인 접근을 제한함으로써 안정성과 유지보수성을 높인다.

2. 상속(Inheritance)

  • 상속은 기존의 클래스를 확장하여 새로운 클래스를 만드는 메커니즘이다.

  • 부모 클래스(상위 클래스, 슈퍼 클래스)의 특성과 동작을 자식 클래스(하위 클래스, 서브 클래스)가 상속받아 재사용할 수 있다.

3. 다형성(Polymorphism)

  • 다형성은 하나의 인터페이스나 기능을 다양한 방식으로 구현하거나 사용할 수 있는 능력을 의미한다.

  • 하나의 메서드 이름이 다양한 객체에서 다르게 동작할 수 있도록 하는 것으로, 오버로딩과 오버라이딩을 통해 구현된다.

  • 유연하고 확장 가능한 코드 작성을 가능하게 하며, 코드의 가독성과 재사용성을 높인다.

4. 추상화(Abstraction)

  • 추상화는 복잡한 시스템이나 개념을 단순화하여 필요한 기능에 집중하는 것을 의미한다.

  • 클래스나 인터페이스를 사용하여 실제 세계의 개념을 모델링하고, 필요한 부분에 대한 명세를 정의한다.

5. 객체(Object)

  • 객체는 클래스로부터 생성된 실체로, 데이터와 해당 데이터를 조작하는 메서드를 가지고 있다.

  • 객체는 상태(데이터)와 행동(메서드)을 가지며, 실제 세계의 개체나 개념을 모델링한다.

  • 객체들 간의 상호작용을 통해 프로그램이 동작하고, 모듈화와 재사용을 높인다.

2) 클래스의 구성 요소

  • 필드(Fidlds) : 클래스에서 사용되는 변수를 말한다. 객체의 상태를 나타내는 데이터를 저장하기 위해 사용된다.

  • 메서드(Methods) : 클래스에서 수행되는 동작이 정의된다. 객체의 동작을 구현하기 위해 사용된다.

  • 생성자(Constructors) : 객체를 초기화하는 역할을 한다. 객체가 생성될 때 자동으로 호출되며, 필드를 초기화하는 등의 작업을 수행한다.

  • 소멸자(Destructors) : 객체가 소멸될 때 호출되는 메서드로, 메모리나 리로스의 해제 등의 작업을 수행한다.

3) 클래스

  • 클래스는 객체를 생성하기 위한 템플릿 또는 설계도 역할을 한다.

  • 클래스는 속성과 동작을 가진다. 속성은 필드로, 동작은 메서드로 표현된다.

  • 객체를 생성하기 위해서는 클래스를 사용하여 인스턴스를 만들어야 한다.

  • 붕어빵틀로 비유하면, 클래스는 붕어빵을 만들기 위한 틀이라고 할 수 있다.

4) 객체

  • 객체는 클래스의 인스턴스이다. 클래스의 실체화된 형태라고 할 수 있다.

  • 객체클래스로부터 생성되며, 각 객체는 독립적인 상태를 가지고 있다. 즉, 객체마다 고유한 데이터를 가질 수 있다.

  • 붕어빵 틀로 비유하면, 객체는 붕어빵이라고 할 수 있다. 붕어빵 틀로 만들어진 실제 붕어빵이 객체라고 볼 수 있다.

5) 클래스 선언과 인스턴스

  • 클래스(Class)는 데이터와 메서드를 하나로 묶은 사용자 정의 타입이다.
// 클래스 구조 기초
class Person
{
    public string Name;
    public int Age;

    public void PrintInfo()
    {
        Console.WriteLine("Name: " + Name);
        Console.WriteLine("Age: " + Age);
    }
}

Person p = new Person();
p.Name = "John";
p.Age = 30;
p.PrintInfo(); // 출력: Name: John, Age: 30

6) 구조체 vs 클래스

  • 구조체와 클래스는 모두 사용자 정의 형식을 만드는 데 사용될 수 있다.

  • 구조체는 값 형식이며, 스택에 할당되고 복사될 때 값이 복사된다.

  • 클래스는 참조 형식이며, 에 할당되고 참조로 전달되므로 성능 측면에서 다소 차이가 있다.

  • 구조체상속을 받을 수 없지만, 클래스단일 상속다중 상속이 가능하다.

  • 구조체작은 크기의 데이터 저장이나 단순한 데이터 구조에 적합하며, 클래스더 복잡한 객체를 표현하고 다양한 기능을 제공하기 위해 사용된다.






02. 접근 제한자

접근 제한자(Access Modifier)는 클래스, 필드, 메서드 등의 접근 가능한 범위를 지정하는 키워드 이다. 접근 제한자는 클래스의 캡슐화를 제어하는 역할을 한다.

  • public : 외부에서 자유롭게 접근이 가능하다.
  • private : 같은 클래스 내부에서만 접근이 가능하다.
  • protected : 같은 클래스 내부와 상속받은 클래스에서만 접근 가능하다.
class Person
{
    public string Name;         // 외부에서 자유롭게 접근 가능
    private int Age;           // 같은 클래스 내부에서만 접근 가능
    protected string Address;  // 같은 클래스 내부와 상속받은 클래스에서만 접근 가능
}






03. 필드와 메서드 ★

  • 클래스필드메서드로 구성된다.
  • 필드클래스 내부에 선언되어 있는 변수로, 클래스의 상태를 나타내는 데이터를 저장한다.
  • 메서드클래스 내부에 선언되어 있는 함수로, 클래스의 동작을 정의하고 실행한다.

1) 필드(Fields)

  • 필드클래스구조체 내에서 객체의 상태(데이터)를 저장하는 변수이다.

  • 객체의 특징이나 속성을 표현하며, 클래스의 멤버 변수로 선언된다.

  • 보통 필드private접근 제한자를 사용하여 외부에서 직접적인 접근을 제한하고, 필요한 경우에는 프로퍼티를 통해 간접적으로 접근할 수 있도록 하는게 좋다.★★★

class Player
{
    // 필드 선언
    private string name;
    private int level;
}

2) 메서드(Methods)

  • 메서드는 클래스나 구조체에서 객체의 동작(기능)을 정의하는 함수이다.

  • 객체의 행동이나 동작을 구현하며, 클래스의 멤버 함수로 선언된다.

  • 메서드는 입력값을 받아서 처리하고, 결과값을 반환할 수도 있다.

  • 객체의 상태를 변경하거나 다른 메서드를 호출하여 작업을 수행한다.

  • 보통 메서드는 public접근 제한자를 사용하여 외부에서 호출할 수 있도록 한다.

class Player
{
    // 필드
    private string name;
    private int level;

    // 메서드
    public void Attack()
    {
        // 공격 동작 구현
    }
}
  • 메서드를 호출하기 위해서는 해당 메서드가 속해 있는 클래스의 인스턴스를 생성해야 한다. 이후 생성된 인스턴스를 통해 메서드를 호출할 수 있다.
Player player = new Player();  // Player 클래스의 인스턴스 생성
player.Attack();  // Attack 메서드 호출





04. 생성자와 소멸자

클래스는 생성자와 소멸자라는 특별한 종류의 메서드를 가질 수 있다. 생성자는 클래스의 인스턴스를 생성할 때 호출되는 메서드이며, 소멸자는 클래스의 인스턴스가 메모리에서 해제될 때 호출되는 메서드이다.

1) 생성자(Constructor)

생성자란?

  • 생성자는 객체가 생성될 때 호출되는 특별한 메서드이다.

  • 클래스의 인스턴스(객체)를 초기화하고, 필요한 초기값을 설정하는 역할을 수행한다.

  • 생성자는 클래스와 동일한 이름을 가지며, 반환 타입이 없다.

  • 객체를 생성할 때 new키워드와 함께 호출된다.

생성자의 특징

  • 객체를 초기화하는 과정에서 필요한 작업을 수행할 수 있다.

  • 생성자는 여러 개 정의할 수 있으며, 매개변수의 개수와 타입에 따라 다른 생성자를 호출할 수 있다. 이를 생성자 오버로딩이라고 한다.

  • 기본적으로 매개변수가 없는 디폴트 생성자가 클래스에 자동으로 생성되지만, 사용자가 직접 정의한 생성자가 있는 경우 디폴트 생성자가 자동으로 생성되지 않는다.

class Person
{
    private string name;
    private int age;

    // 매개변수가 없는 디폴트 생성자
    public Person()
    {
        name = "Unknown";
        age = 0;
    }

    // 매개변수를 받는 생성자
    public Person(string newName, int newAge)
    {
        name = newName;
        age = newAge;
    }

    public void PrintInfo()
    {
        Console.WriteLine($"Name: {name}, Age: {age}");
    }
}

Person person1 = new Person();                     // 디폴트 생성자 호출
Person person2 = new Person("John", 25);           // 매개변수를 받는 생성자 호출

2) 소멸자(Destructor)

소멸자란?

  • 소멸자는 객체가 소멸되는 시점에서 자동으로 호출되는 특별한 메서드이다.

  • 객체의 사용이 종료되고 메모리에서 해제될 때 자동으로 호출되어 필요한 정리 작접을 수행한다.

  • 클래스와 동일한 이름을 가지며, 이름 앞에 ~기호를 붙여 표현한다.

  • 소멸자는 반환 타입이 없고 매개변수를 가질 수 없다.

  • C#에서는 가비지 컬렉터(Garbage Collector)에 의해 관리되는 메모리 해제를 담당하므로, 명시적으로 소멸자를 호출하는 것은 일반적으로 권장되지 않는다.

소멸자의 역할

  • 자원 해제 : 파일 핸들, 네트워크 연결, 데이터베이스 연결 등의 외부 리소스를 사용한 경우, 소멸자를 통해 해당 리소스를 해제할 수 있다.

  • 메모리 해제 : 객체가 사용한 메모리를 해제하고 관련된 자원을 정리할 수 있다.

  • 로깅 및 디버깅 : 객체가 소멸되는 시점에 로깅 작업을 수행하거나 디버깅 정보를 기록할 수 있다.

class Person
{
    private string name;

    public Person(string newName)
    {
        name = newName;
        Console.WriteLine("Person 객체 생성");
    }

    ~Person()
    {
        Console.WriteLine("Person 객체 소멸");
    }
}





05. 프로퍼티(Property) ★

  • 프로퍼티클래스 멤버로서, 객체의 필드 값을 읽거나 설정하는데 사용되는 접근자(Accessor) 메서드의 조합이다.
  • 객체의 필드에 직접 접근하지 않고, 간접적으로 값을 설정하거나 읽을 수 있도록 한다.
  • 필드에 대한 접근 제어데이터 유효성 검사 등을 수행할 수 있다.
  • 프로퍼티필드와 마찬가지로 객체의 상태를 나타내는 데이터 역할을 하지만, 외부에서 접근할 때 추가적인 로직을 수행할 수 있다.

1) 프로퍼티 구문

  • 프로퍼티getset접근자를 사용하여 값을 읽고 설정하는 동작을 정의한다.

  • get접근자는 프로퍼티의 값을 반환하고, set접근자는 프로퍼티의 값을 설정한다.

  • 필요에 따라 get또는 set접근자 중 하나를 생략하여 읽기 전용 또는 쓰기 전용 프로퍼티를 정의할 수 있다.

[접근 제한자] [데이터 타입] 프로퍼티명
{
    get
    {
        // 필드를 반환하거나 다른 로직 수행
    }
    set
    {
        // 필드에 값을 설정하거나 다른 로직 수행
    }
}

2) 프로퍼티 사용 예시

  • Player클래스의 이름과 레벨을 나타내는 name과 level필드를 캡슐화 한 프로퍼티의 예시
class Person
{
    private string name;
    private int age;

    public string Name
    {
        get { return name; }
        set { name = value; }
    }

    public int Age
    {
        get { return age; }
        set { age = value; }
    }
}

Person person = new Person();
person.Name = "John";   // Name 프로퍼티에 값 설정
person.Age = 25;        // Age 프로퍼티에 값 설정

Console.WriteLine($"Name: {person.Name}, Age: {person.Age}");  // Name과 Age 프로

3) 프로퍼티 접근 제한자 적용 & 유효성 검사 예제

class Person
{
    private string name;
    private int age;

    public string Name
    {
        get { return name; }
        private set { name = value; }
    }

    public int Age
    {
        get { return age; }
        set
        {
            if (value >= 0)
                age = value;
        }
    }
}

Person person = new Person();
person.Name = "John";     // 컴파일 오류: Name 프로퍼티의 set 접근자는 private입니다.
person.Age = -10;         // 유효성 검사에 의해 나이 값이 설정되지 않습니다.

Console.WriteLine($"Name: {person.Name}, Age: {person.Age}");  
// Name과 Age 프로퍼티에 접근하여 값을 출력합니다.

4) 자동 프로퍼티(Auto Property)

  • 자동 프로퍼티는 프로퍼티를 간단하게 정의하고 사용할 수 있는 편리한 기능이다.

  • 필드의 선언과 접근자 메서드의 구현을 컴파일러가 자동으로 처리하여 개발자가 간단한 구문으로 프로퍼티를 정의할 수 있다.

자동 프로퍼티 구문

[접근 제한자] [데이터 타입] 프로퍼티명 { get; set; }

자동 프로퍼티 예시

class Person
{
    public string Name { get; set; }
    public int Age { get; set; }
}

Person person = new Person();
person.Name = "John";     // 값을 설정
person.Age = 25;          // 값을 설정

Console.WriteLine($"Name: {person.Name}, Age: {person.Age}");  // 값을 읽어 출력





Tip

  • 클래스와 객체를 사용하여 프로그램을 작성할 때, 객체 지향 프로그램(OOP)의 원칙을 지키도록 노력해야 한다. 캡슐화, 상속관계, 다형성 등 OOP 개념을 이해하고 활용하여 유지보수성이 높고 재사용 가능한 코드를 작성할 수 있다.

  • Properties를 사용하여 필드 접근을 제어하면, 코드의 안정성과 가독성을 높일 수 있다.

  • 클래스의 접근 제한자를 적절히 사용하여 필요한 부분만 외부에서 접근 가능하도록 성정하는 것이 좋다.







📌 상속과 다형성

01. 상속

상속(Inheritance)은 객체지향 프로그래밍에서 중요한 개념

  • 상속은 기존의 클래스(부모 클래스 또는 상위 클래스)를 확장하거나 재사용하여 새로운 클래스(자식 클래스 또는 하위 클래스)를 생성하는 것이다.
  • 자식 클래스는 부모 클래스의 멤버(필드, 메서드, 프로퍼티 등)를 상속받아 사용할 수 있다.
  • 상속을 통해 부모 클래스의 기능을 확장하거나 수정하여 새로운 클래스를 정의할 수 있다.

1) 상속의 장점

  • 코드의 재사용성 : 상속을 통해 기존 클래스의 코드를 재사용할 수 있으므로, 반복적인 코드 작성을 줄일 수 있다.

  • 계층 구조의 표현 : 클래스 간의 계층 구조를 표현하여 코드의 구조를 명확하게 표현할 수 있다.

  • 유지보수성의 향상 : 상속을 통해 기존 클래스의 수정이 필요한 경우, 해당 클래스만 수정하면 된다. 이로써 코드의 유지보수성이 향상된다.

2) 상속의 종류

  • 단일 상속 : 하나의 자식 클래스가 하나의 부모 클래스만 상속받는 것을 말한다. C#에서는 단일 상속만을 지원한다.

  • 다중 상속 : 하나의 자식 클래스가 여러 개의 부모 클래스를 동시에 상속받는 것을 말한다. C#은 다중 상속을 지원하지 않는다.

  • 인터페이스 상속 : 클래스가 인터페이스를 상속받는 것을 말한다. 인터페이스는 다중 상속을 지원하며, 클래스는 하나의 클래스와 여러 개의 인터페이스를 상속받을 수 있다.

3) 상속의 특징

  • 부모 클래스의 멤버에 접근 : 자식 클래스는 상속받은 부모 클래스의 멤버에 접근할 수 있으며, 이를 통해 부모 클래스의 기능을 재사용할 수 있다.

  • 메서드 재정의 : 자식 클래스는 부모 클래스의 메서드를 재정의하여 자신에게 맞게 수정할 수 있다. 이를 통해 다형성(Polymorphism)을 구현할 수 있다.

  • 상속의 깊이 :

  1. 클래스는 다수의 계층적인 상속을 가질 수 있다. 부모 클래스가 또 다른 클래스의 자식 클래스가 될 수 있으며, 이를 통해 상속의 계층 구조를 형성할 수 있다.

  2. 상속의 깊이가 깊어질수록 클래스 간의 관계가 복잡해질 수 있으므로, 적절한 상속의 깊이를 유지하고 상속을 적절하게 사용하는 것이 중요하다.

4) 접근 제한자와 상속

  • 상속 관계에서 멤버의 접근 제한자는 중요한 역할을 한다. 부모 클래스의 멤버의 접근 제한자에 따라 자식 클래스에서 해당 멤버에 접근할 수 있는 범위가 결정된다.

  • 접근 제한자를 통해 상속된 멤버의 가시성을 조절하여 캡슐화와 정보 은닉을 구현할 수 있다.

예제 코드

// 부모 클래스
public class Animal
{
    public string Name { get; set; }
    public int Age { get; set; }

    public void Eat()
    {
        Console.WriteLine("Animal is eating.");
    }

    public void Sleep()
    {
        Console.WriteLine("Animal is sleeping.");
    }
}

// 자식 클래스
public class Dog : Animal
{
    public void Bark()
    {
        Console.WriteLine("Dog is bark.");
    }
}

public class Cat : Animal
{
    public void Sleep()
    {
        Console.WriteLine("Cat is sleeping.");
    }

    public void Meow()
    {
        Console.WriteLine("Cat is meow.");
    }
}

// 사용 예시
Dog dog = new Dog();
dog.Name = "Bobby";
dog.Age = 3;

dog.Eat();      // Animal is eating.
dog.Sleep();    // Animal is sleeping.
dog.Bark();     // Dog is barking

Cat cat = new Cat();
cat.Name = "KKami";
cat.Age = 10;

cat.Eat();
cat.Sleep();
cat.Meow();





02. 다형성

같은 타입이지만 다양한 동작을 수행할 수 있는 능력

1) 가상(Virtual) 메서드

  • 가상 메서드는 기본적으로 부모 클래스에서 정의되고 자식 클래스에서 재정의할 수 있는 메서드이다.

  • 가상 메서드는 virtual키워드를 사용하여 서언되며, 자식 클래스에서 필요에 따라 재정의 될 수 있다.

  • 이를 통해 자식 클래스에서 부모 클래스의 메서드를 변경하거나 확장할 수 있다.


public class Unit
{
    public virtual void Move()
    {
        Console.WriteLine("두발로 걷기");
    }

    public void Attack()
    {
        Console.WriteLine("Unit 공격");
    }
}

public class Marine : Unit
{

}

public class Zergling : Unit
{
    public override void Move()
    {
        Console.WriteLine("네발로 걷기");
    }
}

// 사용 예시
// #1 참조형태와 실형태가 같을때
Marine marine = new Marine();
marine.Move();
marine.Attack();

Zergling zergling = new Zergling();
zergling.Move();
zergling.Attack();

// #2 참조형태와 실형태가 다를때
List<Unit> list = new List<Unit>();
list.Add(new Marine());
list.Add(new Zergling());

foreach (Unit unit in list)
{
    unit.Move();
}

2) 추상(Abstract)클래스와 메서드

  • 추상 클래스는 직접적으로 인스턴스를 생성할 수 없는 클래스

  • 주로 상속을 위한 베이스 클래스로 사용된다.

  • 추상 클래스는 abstract키워드로 사용하여 선언되며, 추상 메서드를 포함할 수 있다.

  • 추상 메서드는 구현부가 없는 메서드로, 자식 클래스에서 반드시 구현됭야 한다.

abstract class Shape
{
    public abstract void Draw();
}

class Circle : Shape
{
    public override void Draw()
    {
        Console.WriteLine("Drawing a circle");
    }
}

class Square : Shape
{
    public override void Draw()
    {
        Console.WriteLine("Drawing a square");
    }
}

class Triangle : Shape
{
    public override void Draw()
    {
        Console.WriteLine("Drawing a triangle");
    }
}

List<Shape> list = new List<Shape>();
list.Add(new Circle());
list.Add(new Square());
list.Add(new Triangle());

foreach (Shape shape in list )
{
    shape.Draw();
}

3) 오버라이딩과 오버로딩

오버라이딩(Overriding)과 오버로딩(Overloading)은 객체지향 프로그래밍에서 다른 개념을 나타내는 두 용어 이다.

오버라이딩(Overriding)

  • 부모 클래스에서 이미 정의된 메서드를 자식 클래스에서 재정의하는 것을 의미한다.

  • 이는 상속 관계에 있는 클래스 간에 발생하며, 메서드의 이름, 매개변수 및 반환타입이 동일해야 한다.

  • 오버리이딩을 통해 자식 클래스는 부모 클래스의 메서드를 재정의하여 자신에게 맞는 동작을 구현 할 수 있다.

public class Shape
{
    public virtual void Draw()
    {
        Console.WriteLine("Drawing a shape.");
    }
}

public class Circle : Shape
{
    public override void Draw()
    {
        Console.WriteLine("Drawing a circle.");
    }
}

public class Rectangle : Shape
{
    public override void Draw()
    {
        Console.WriteLine("Drawing a rectangle.");
    }
}

Shape shape1 = new Circle();
Shape shape2 = new Rectangle();

shape1.Draw();  // Drawing a circle.
shape2.Draw();  // Drawing a rectangle.

오버로딩(Overloading)

  • 동일한 메서드 이름을 가지고 있지만, 매개변수의 개수, 타입 또는 순서가 다른 여러 개의 메서드를 정의하는 것을 의미한다.

  • 오버로딩을 통해 동일한 이름을 가진 메서드를 다양한 매개변수 조합으로 호출할 수 있다.

public class Calculator
{
    public int Add(int a, int b)
    {
        return a + b;
    }

    public int Add(int a, int b, int c)
    {
        return a + b + c;
    }
}

Calculator calc = new Calculator();
int result1 = calc.Add(2, 3);         // 5
int result2 = calc.Add(2, 3, 4);      // 9






📌 고급 문법 및 기능

01. 제너릭

  • 제너릭은 클래스나 메서드를 일반화시켜 다양한 자료형에 대응할 수 있는 기능이다.
  • 제너릭을 사용하면 코드의 재사용성을 높일 수 있다.
  • C#에서는 <T><T>형태의 키워드를 이용하여 제너릭을 선언하다.
  • 제너릭 클래스나 메서드에서 사용할 자료형은 선언 시점이 아닌 사용 시점에 결정된다.
  • 제너릭 클래스나 메서드를 사용할 때는 <T><T>대신 구체적인 자료형을 넣어준다.
  // 제너릭 클래스 선언 예시
class Stack<T>
{
    private T[] elements;
    private int top;

    public Stack()
    {
        elements = new T[100];
        top = 0;
    }

    public void Push(T item)
    {
        elements[top++] = item;
    }

    public T Pop()
    {
        return elements[--top];
    }
}

// 제너릭 클래스 사용 예시
Stack<int> intStack = new Stack<int>();
intStack.Push(1);
intStack.Push(2);
intStack.Push(3);
Console.WriteLine(intStack.Pop()); // 출력 결과: 3
  • 제너릭을 두개 이상 사용하는 예
class Pair<T1, T2>
{
    public T1 First { get; set; }
    public T2 Second { get; set; }

    public Pair(T1 first, T2 second)
    {
        First = first;
        Second = second;
    }

    public void Display()
    {
        Console.WriteLine($"First: {First}, Second: {Second}");
    }
}
  
Pair<int, string> pair1 = new Pair<int, string>(1, "One");
pair1.Display();

Pair<double, bool> pair2 = new Pair<double, bool>(3.14, true);
pair2.Display();

출력

Pair<int, string> pair1 = new Pair<int, string>(1, "One");
pair1.Display();

Pair<double, bool> pair2 = new Pair<double, bool>(3.14, true);
pair2.Display();





02. out, ref키워드

1) 사용법

  • out, ref키워드는 메서드에서 매개변수를 전달할 때 사용한다.

  • out키워드는 메서드에서 반환 값매개변수전달하는 경우에 사용한다.

  • ref키워드는 메서드에서 매개변수를 수정하여 원래 값영향을 주는 경우 사용한다.

  • out, ref키워드를 사용하면 메서드에서 값을 반환하는 것이 아니라, 매개변수를 이용하여 값을 전달할 수 있다.

  
// out 키워드 사용 예시
void Divide(int a, int b, out int quotient, out int remainder)
{
    quotient = a / b;
    remainder = a % b;
}

int quotient, remainder;
Divide(7, 3, out quotient, out remainder);
Console.WriteLine($"{quotient}, {remainder}"); // 출력 결과: 2, 1

// ref 키워드 사용 예시
void Swap(ref int a, ref int b)
{
    int temp = a;
    a = b;
    b = temp;
}

int x = 1, y = 2;
Swap(ref x, ref y);
Console.WriteLine($"{x}, {y}"); // 출력 결과: 2, 1
  





2) 주의 사항

  • 값의 변경 가능성 : ref매개변수를 사용하면 메서드 내에서 해당 변수의 값을 직접 변경할 수 있다. 이는 예기치 않은 동작을 초래할 수 있으므로 주의가 필요하다.

  • 성능 이슈 : ref매개변수는 값에 대한 복사 없이 메서드 내에서 직접 접근할 수 있기 떄문에 성능상 이점이 있다. 그러나 너무 많은 매개변수 ref로 전달하면 코드의 가독성이 떨어지고 유지보수가 어려워질 수 있다. 적절한 상황에서 ref를 사용하는 것이 좋다.

  • 변수 변경 여부 주의 : out매개변수는 메서드 내에서 반드시 값을 할당해줘야 한다. 따라서 out매개변수를 전달 할 때 해당 변수의 이전 값이 유지되지 않으므로 주의해야 한다.







📌 3주차 숙제 : 조금 더 복잡한 게임 만들기

스네이크 게임 만들기






블랙잭 게임 만들기

profile
No Easy Day

0개의 댓글