본문 바로가기

Unity 개발 공부

[내일배움캠프 사전캠프] 4일차 C# 기초문법 복습 및, 활용해보기 (25.03.26)

입력 받기.

Console.ReadLine 매서드 이용하여 사용자의 입력을 문자열로 받을 수 있다.

 

string name = Console.ReadLine();

Console.WriteLine($"Hello, {name}!");

 

숫자 입력 받기

입력받은 문자열을 숫자로 변환하려면, int.Parse, Convert.ToInt32 메서드 사용가능.

 

int number = int.Parse(Console.ReadLine()); // int.Parse( ) 소괄호 안에, 메서드도 넣을 수 있음..

Console.WriteLine($"You entered: {number}");

 

...

 

배열 

 

선언, 초기화 방법 두가지

 

int[ ] numbers = new int [5] ;

numbers[0] = 10;

numbers[1] = 20;

numbers[1] = 30;

...

 

혹은

 

int [ ] numbers = { 10, 20, 30, 40, 50 } ;

배열 접근 및 순회 방법

int[] numbers = { 10, 20, 30, 40, 50 };
for (int i = 0; i < numbers.Length; i++) // numbers.Length 는 5다 5개가 있기때문, 
{
    Console.WriteLine(numbers[i]);
}

 

 

클래스

먼저 복습
public class Character
{
    public string Name { get; set; } // 명시적으로 필드선언한것이라 접근이 힘듬. 속성식 간단하게 나타낸것
    public int Level { get; set; } // 마찬가지.

    public void Introduce()
    {
        Console.WriteLine($"이름: {Name}, 레벨: {Level}");
    }
}

class Program
{
    static void Main()
    {
        Character ch = new Character();   // 🧱 여기서 객체 ch가 만들어짐
        ch.Name = "예은";                 // ✏️ ch의 Name 속성에 값을 넣음
        ch.Level = 5;                     // ✏️ ch의 Level 속성에도 값 넣음
        ch.Introduce();                   // 📢 메서드 실행
    }
}

ch. 라는 객체는 .(닷)을 통해 Character라는 클래스 내의 멤버들을 꺼내 쓸수있는데
필드, 속성, 생성자, 메서드가 그러하다. 
다만, 필드는 private이므로 ch. 로 가져올 수 없다. 

 

여기서 필드를 자동 구현한게 위에

public string Name { get; set; } 인데 속성 내부에서 정교하게 컨트롤을 좀더 가능하게 하려면 이렇게도 표현할 수 있다.

public class Character
{
    // 필드
    private string name;
    private int level;

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

    public int Level
    {
        get { return level; }
        set { level = value; }
    }

    // 메서드
    public void Introduce()
    {
        Console.WriteLine($"이름: {Name}, 레벨: {Level}");
    }

    // 생성자
    public Character()
    {
        name = "이름 없음";
        level = 1;
    }
}

이렇게 하면 속성에 조건, 로그 제어로직을 자유롭게 넣을 수 있다.

set {
    if (value == " ") name = "이름 없음";
    else name = value;
}

 

클래스 내에 속성, 생성자를 쓸때를 구분해보자.

우선 필드만 사용할때와 속성을 사용할때를 구분해보자.

- 필드만 사용시, 외부접근 불가능 / 속성쓸때는 가능하다. (객체.속성) 형태로 접근.

 

해당 코드를 보면, 

public class Character
{
    private string name;
    private int level;

    public Character(string inputName, int inputLevel)
    {
        name = inputName;
        level = inputLevel;
    }

    public void Introduce()
    {
        Console.WriteLine($"이름: {name}, 레벨: {level}");
    }
}

 

속성이 없으므로 외부에서 접근 x

ch.name 이나 ch.level로 접근이 불가능하고

무조건 메서드로 보여줘야한다.
Character ch = new Character(예은, 5);

ch.Introduce(); 를 써서 말이다.

메서드가 getter 역할 또는 setter 역할을 하도록 만들어야한다. 

 

그러나 속성을 사용하면, 

public class Character
{
    public string Name { get; set; }
    public int Level { get; set; }

    public Character(string name, int level)
    {
        Name = name;
        Level = level;
    }
}

외부에서 바로

Character ch = new Character("예은, 5);

Console.WriteLine(ch.Name);

ch.Level = 10;

이런식으로 접근도 되고 수정도 된다.

 

그런데 보면, 속성을 쓰면 getter, setter가 존재하니 굳이 메서드가 없어도 될것같고, 생성자도 필요없어보인다. 
그런데
한 클래스에 속성, 생성자, 메서드가 같이 쓰일 수 있다.

속성 -> 이름, 레벨, 체력 등 정보 보관

생성자 -> 캐릭터 만들때 초기값 넣기

메서드 -> 행동정의 (공격, 회복, 레벨업) 등이다.

인데

public class Character
{
    // 속성 (데이터)
    public string Name { get; set; }
    public int Level { get; set; }
    public int HP { get; set; }

    // 생성자 (초기화)
    public Character(string name, int level)
    {
        Name = name;
        Level = level;
        HP = 100;  // 기본 체력
    }

    // 메서드 (동작)
    public void TakeDamage(int damage)
    {
        HP -= damage;
        if (HP < 0) HP = 0;
        Console.WriteLine($"{Name}이(가) {damage} 데미지를 입었습니다. (남은 HP: {HP})");
    }

    public void Heal(int amount)
    {
        HP += amount;
        if (HP > 100) HP = 100;
        Console.WriteLine($"{Name}이(가) {amount} 회복했습니다. (현재 HP: {HP})");
    }

    public void Introduce()
    {
        Console.WriteLine($"[이름: {Name}] [레벨: {Level}] [HP: {HP}]");
    }
}

이렇게 하고 사용예로

Character ch = new Character("예은", 3);

ch.Introduce();      // 출력: 이름, 레벨, 체력
ch.TakeDamage(30);   // 행동: 데미지 입음
ch.Heal(20);         // 행동: 체력 회복
ch.Level = 4;        // 속성으로 직접 레벨 변경

이런식으로 
속성에 접근해서 직접 이름, 레벨, hp를 변경 가능할 수도 있으며,
생성자를 이용해 사용자가 타이핑으로 이름과 레벨을 정할 수 있게 해주며,
데미지를 입거나, 힐을 받거나, 자기소개를 하는 행동을 하고자 할때 다음과 같이 코드를 짤 수 있다.

그다음은 속성에서 private set, readonly, init 에 대해서 배워보자

 

public string Name { get; private set; }

외부에서는 Name을 읽을 수 는 있지만, 바꿀 수는 없다.

클래스 내부에서는 set 가능하다.

public class Character
{
    public string Name { get; private set; }

    public Character(string name)
    {
        Name = name; // 클래스 내부에서 set 가능
    }
}

이러면,

 

Character ch = new Character("예은");
Console.WriteLine(ch.Name); // ✅ 읽기 가능
ch.Name = "예지";           // ❌ 오류! set이 private이라 외부에서 못 바꿈

 

상태를 한번 설정하면 외부에서 못 바꾸게 보호하고싶을때 유용하다.

 

다음으로,

readonly 는

private readonly string id;

필드 에 붙이는 키워드로, 값을 생성자에서 딱 한번 설정 가능 하며 수정은 불가하다.

 

public class Character
{
    private readonly string id;

    public Character(string inputId)
    {
        id = inputId;   // ✅ 생성자에서만 설정 가능
    }

    public void ShowId()
    {
        Console.WriteLine(id);
    }
}

 

하고

 

Character ch = new Character("ABC123");
ch.ShowId();            // ✅ 출력 가능
// ch.id = "XYZ";       // ❌ 오류! readonly는 생성자 밖에서 수정 불가

 

변하지 않아야 하는 고유값에 자주 쓴다( 캐릭터 고유 id)

 

init - 객체 초기화 시에만 값 설정 가능하다.

public string Name { get; init; }

 

set 대신 init을 쓰면

생성자 또는

객체 초기화 문법

이때만 값을 줄 수 있고 그 이후에는 수정 불가.

 

예를들어,

public class Character
{
    public string Name { get; init; }
    public int Level { get; init; }
}

하면

 

var ch = new Character { Name = "예은", Level = 5 }; // ✅ OK
// ch.Name = "예지";    // ❌ 오류! init은 객체 생성 이후 수정 불가

불변 객체를 만들때 아주 유용하다.

 

정리하자면

 

private set 은 속성에 적용되며, 클래스 내부 어디서든 가능, 외부에서는 수정 불가능, 값은 바뀔수 있으나 외부 제어는 방지한다.

 

readonly는 필드에서 적용되며, 생성자에서 한번만 가능, 외부에서 수정 불가능하며, 고정값, 변하지 않아야 하는 데이터

 

init은 속성에서 적용되며, 객체 생성시에만 가능, 외부수정 불가능하며, 한번 초기화만 허용한다.

 

따라서, 외부에서 읽기만 가능하고 바꾸면 안되는 속성은 private set

한번 정해지면 절대 바뀌면 안되면, readonly , 즉 생성자에서만 ,, 생성될때 딱한번만 값 설정가능하다. 필드에만 적용된다는 점도 중요.

속성은 그대로 두되, 객체 초기화 시점까지만 수정가능하면 init 을 쓴다. 객체를 만들때 중괄호 안에서만 값을 줄 수 있다는 소리다. 객체를 만들고나면 끝이난다는 소리다,,

var ch = new Character { Name = "예은", Level = 5 };