C#-(2) 기본 개념

10 분 소요

연산자

연산자 개요

  • 변수 데이터를 연산해 다양한 결과를 얻기 위해 사용
  • 결과 값을 대입하는 대입 연산자부터 사칙연산을 하는 산술 연산자 등 제공 그림5

대입(할당) 연산자

  • 결과값을 댕비하는 연산자로 여러 연산을 축약한 대입 연산자도 제공 그림6

비교(관계) 연산자

  • 양쪽의 값을 비교하여 결과를 참(true) 또는 거짓(false)으로 나타내는 연산자 그림7

비교(관계) 연산자

  • 양쪽의 값을 비교하여 결과를 참(true) 또는 거짓(false)으로 나타내는 연산자 그림8

조건(삼항) 연산자

  • 조건식을 사용해 조건식의 참, 거짓 여부에 따라 다른 결과 값 대입 그림9

비트 연산자

  • 비트 단위의 데이터 연산에 사용
  • 시프트 연산의 장점 : 연산 속도가 빠르다
  • 시프트 연산의 단점 : 머리로 계산이 잘 안된다 그림10

비트 논리 연산자

그림11

연산자 우선순위

  • 연산자마다 우선순위가 정해져 있다
  • 우선순위가 같을 경우 왼쪽의 연산자를 먼저 계산한다
  • 괄호 안에 있는 연산자가 우선 계산된다
  • 우선순위가 헷갈리면 괄호로 구분하는게 최고다 그림12

조건문

조건문 개요

  • 조건문은 설정한 조건이 참(true) 또는 거짓(false)일 때 코드를 실행하거나 실행하지 않고 넘어가서 프로그램의 흐름을 여러 갈래로 나누는 제어문이다.
  • 조건문에는 if와 switch-case가 있으며, if의 경우 if, else if, else로 나눌 수 있다 그림13

if

  • if의 조건이 참이면 if 조건식 뒤의 중괄호 내부를 실행하고, 거짓이면 실행하지 않고 넘어간다 그림14

SerializeField 어트리뷰트

  • ex) [SerializeField]
  • ex) private int x = 10;
  • 클래스 멤버 변수를 선언할 때 변수 앞 또는 바로 윗줄에 작성하면 유니티 에디터 Inspector View에서 해당 클래스 멤버 변수 값을 설정할 수 있다.

if-else

  • if의 조건이 참(true)이면 if 중괄호 내부를 실행하고, 거짓(false)이면 else 중괄호 내부를 실행한다. 그림15

if-else if - else

  • if의 조건이 참(true)이면 if 내부를 실행하고, 거짓(false)이면 else if의 조건 2를 실행한다
  • else if의 조건 2가 참(true)이면 else if 내부를 실행하고, 거짓이면(false)이면 else를 실행한다 그림16

switch - case

  • switch에 조건을 검사할 변수를 설정한다
  • 조건에 해당하는 것이 case 뒤에 있는 값이다
  • 위의 조건을 모두 만족하지 않을 때 제일 아래에 작성된 default가 실행된다 (if 조건문의 else와 같은 역할을 수행)
  • switch - case에서 break는 중단의 역할을 하기 때문에 break가 없다면 다른 case의 조건도 이어서 실행하게 된다 그림17

반복문

반복문 개요

  • 반복문은 설정한 조건이 거짓이 될 때까지 코드 블록 내부를 반복해서 실행한다
  • 반복문에는 for, while, do-while이 있다 그림18

for

  • for 괄호 내부에 초기화, 조건, 증감 연산자와 같이 3개의 연산자를 작성하며, 초기화한 변수가 반복문 내부를 1회 실행할 때만다 증감 연산자에 의해 값이 바뀜
  • 이 값이 조건을 만족하지 않을 때까지 반복해서 실행한다. 그림19 그림20

while

  • for와 다르게 괄호 내부에 조건만 들어간다
  • 조건을 만족하지 않을 때까지 반복 실행하는 것은 동일하다
  • 조건에 사용되는 변수의 초기화와 증감 연산은 알아서 작성해야한다
  • 보통 초기화는 while()문 위의 작성하며, 증감 연산은 while()문 내부의 가장 아래에 작성한다
  • 실행 구조는 for문과 유사하다. 그림21 그림22 그림23

do-while

  • for, while문은 조건을 먼저 검사하기 때문에 조건이 맞지 않으면 단 1번도 실행되지 않는다.
  • 반면, do-while은 일단 한번은 조건 없이 실행하고, 그 후에 조건을 검사해 반복해서 실행한다. 그림24 그림25

무한 루프

  • 반복문은 정해진 회수만큼 반복한 후 종료하지만, 이를 정해진 회수 없이 무한하게 실행하도록 할 수 있다
  • 반복문 내부 또는 다른 곳에서 이 반복문을 종료시킬 수 있는 코드를 반드시 작성해야한다. 그림26

무한 루프 사용 방법

  • for 반복문은 세미콜론 사이에 들어가는 문장을 작성하지 않으면 된다
  • while, do-while은 조건에 true를 작성해 조건이 계속 참이 되도록 설정한다

점프문 break, continue

  • 흐름을 끊고 프로그램의 실행 위치를 원하는 곳으로 이동시킨다
  • break : 현재 실행중인 반복문이나 switch문의 실행을 중단할 때 사용한다
  • continue : 반복문에서 현재 조건을 건너뛴다

배열

배열이란?

  • 같은 형식의 데이터를 한 그룹으로 묶어서 사용하는 것

배열이 필요한 이유?

  • 5마리의 적이 있다고 가정할 때, 5마리의 적의 체력을 담는 변수 선언 그림27
  • 만약 이러한 적이 50마리라고 한다면? 50개의 변수 선언 ?
  • 변수를 50개 선언해야할까?

배열의 선언

그림28

배열에 값 저장하기

그림29

배열의 장점

  • 선언 뿐만 아니라 사용할 때도 개수만큼의 줄 수가 필요한 변수와 달리 배열은 반복문을 이용해 한번에 사용 가능 그림30

배열의 초기화

  • 첫번째 방법은 배열의 원소 개수를 명시, 그 뒤에 중괄호 { 와 }로 둘러싸인 블록을 붙인 뒤, 블록 사이에 배열의 각 원소에 입력될 데이터 입력 그림31

  • 두번째 방법은 첫번째 방법에서 배열의 용량을 생략 그림32

  • 세번째 방법은 new 연산자, 형식과 괄호 ‘[’ ‘]’배열의 용량 모두 생략 그림33

System.Array

  • .NET 프레임워크의 CTS(Common Type System)에서 제공하는 배열
  • Array 클래스의 주요 메소드와 프로퍼티 그림34

2차원 배열의 선언

  • (세로 +가로) 형태로 된 배열로 차원의 크기를 콤마(,)로 구분해서 입력 그림35 그림36

가변 배열(Jagged Array)

  • Jagged의 뜻은 “들쭉날쭉한” 이라는 뜻
  • 말 그대로 1차원의 크기를 들쭉날쭉 다르게 설정할 수 있다 그림37

메소드

메소드란?

  • 객체 지향 프로그래밍 언어에서 사용하는 용어
  • 유사한 용어 (사용하는 언어에 따라 다르게 부르기도 한다)
  • 함수 (Function)
  • 서브루틴 (SubRoutine)
  • 프로시져 (Procedure)
  • 서브 프로그램 (SubProgram)

메소드 정의

  • “방법”이라는 뜻으로 객체의 일을 처리하는 방법을 정의
  • 일련의 코드를 하나의 이름 아래 묶은 것
  • 묶어 놓은 코드는 메소드의 이름을 불러 내부 코드들을 실행할 수 있다 그림38

메소드의 예

그림39

메소드의 장점

  • 일련의 코드를 묶어두고, 이름을 불러 내부 코드를 실행하기 때문에 동일한 내용의 코드를 반복해서 작성하는 수고가 적어진다

Return 이란?

  • return이 호출되면 메소드를 종료, 프로그램의 흐름을 호출자에게 돌려준다
  • 메소드 내부에서 변환된 특정 데이터를 반환하는 용도로 사용

매개 변수를 사용하는 이유?

  • 매개 변수가 없으면 단순히 같은 내용의 코드를 반복 재생하는 정도
  • 매개 변수가 있으면 메소드 내부에서 연산되는 결과가 다양하게 변화

값에 의한 전달 (Call By Value)

  • Awake() 메소드의 a,b 값을 Add() 메소드의 매개 변수로 넘긴다면
  • 넘겨지는 매개 변수 a, b는 Add() 메소드 안으로 들어가는 것일까 ? 그림40

참조에 의한 전달 (Call By Reference)

  • 값에 의한 전달처럼 매개 변수가 변수나 상수로부터 값을 복사하는 것이 아닌 원본 변수를 직접 참조하는 방식
  • 원본 변수를 참조 중이기 때문에 매개 변수를 수정하면 원본이 수정된다
  • 사용방법 : 메소드의 정의와 호출에서 매개 변수 앞에 ref 키워드 사용 그림41

출력 전용 매개 변수

  • return은 하나의 결과만 반환하는 것이 가능하다
  • 2개 이상의 결과를 반환할 때는 ?
  • 변경된 값이 유지되니까 ref 키워드를 사용할까? 그림42

  • 출력 전용 매개 변수인 out 키워드 사용
  • ref 매개 변수는 메소드 내부에서 결과를 저장하지 않아도 컴파일러가 아무런 경고도 하지 않는 반면,
  • out 매개 변수는 메소드 내부에서 결과를 저장하지 않으면 컴파일 에러가 발생 (개발자의 실수를 줄여준다) 그림43

메소드 오버로딩

  • 두 수를 더하는 Add() 메소드를 구현하는 경우
  • 더하는 데이터 타입이 정수일 수도 있고, 실수일 수도 있다 그림44
  • 동일한 메소드 이름으로 여러 종류의 메소드를 구현하는 것
  • 매개 변수의 개수와 형식을 분석하여 메소드를 선택
  • 반환 형식은 고려하지 않기 때문에 반환 형식만 다를 경우는 구분하지 못한다

가변 길이 매개 변수

  • 개수가 유연하게 변할 수 있는 매개 변수
  • 변수의 길이가 다른 메소드가 아주 많이 필요한 경우 사용 그림45

명명된 매개 변수

  • 일반적으로 매개 변수에 데이터를 할당할 때 순서에 의거하여 할당하는 반면
  • 순서에 상관 없이 매개 변수의 이름에 근거하여 데이터를 할당하는 방법
  • 코드의 길이는 길어지지만 코드의 가독성이 높아진다 그림46

선택적 매개 변수

  • 매개 변수를 특정 값으로 초기화 하지 않았을 때 기본 값을 할당하는 것
  • 필요에 따라 매개 변수에 데이터를 할당하거나 할당하지 않을 때 사용
  • 선택적 매개 변수는 항상 필수 매개 변수 뒤에 와야 한다 그림47

선택적 매개 변수의 예

그림48

  • 주의! 메소드 오버로딩과 선택적 매개 변수를 아래와 같이 섞어쓰지 않도록 한다 그림49

객체 지향 프로그래밍

  • 객체를 기반으로 하는 프로그래밍(OOP, Object Oriented Programming)
  • 프로그램을 여러 개의 독립된 객체 단위로 분할해 각각의 객체들이 메시지를 주고 받고, 데이터를 처리할 수 있다
  • 프로그램 개발을 유연하게 할 수 있어 게임과 같이 유지/보수가 많고, 대규모의 소프트웨어 개발에 많이 사용된다.

객체란?

  • 세상의 모든 것을 지칭 (사람, 자동차 등)
  • 추상적인 개념 (객체의 특징만 뽑아서 사용 - 속성과 기능으로 구분)
  • 자동차 속성 : 바퀴(개수, 크기, 재질 등), 핸들(반지름, 색상), 기어, 브레이크, 가속페달 등
  • 자동차 기능 : 전진, 후진, 방향 전환, 감속 등

클래스(Class)

  • 객체를 표현하는 속성(변수)과 기능(메서드)을 하나의 집합으로 묶는 단위
  • 타코야끼를 만들 때, 타코야끼 틀에 반죽 물과 문어를 넣고 타지 않게 돌리며 굽는다.
  • 타코야끼 틀 = 클래스
  • 만들어진 타코야끼 = 객체

클래스의 정의

그림50

클래스의 예

  • 아래 정보를 기반으로 하는 플레이어 캐릭터 클래스 작성
  • 속성 (변수, 데이터) : 플레이어 아이디, 체력
  • 기능 (메소드) : 데미지를 입어 체력 감소 그림51

클래스의 문법

그림52

멤버 변수 (필드,Field)

  • 클래스에 소속된 변수로 클래스의 속성을 저장, 사용하기 위한 용도
  • 같은 클래스에 소속되어 있는 메소드는 이 변수를 조건 없이 사용 가능 그림53

멤버 함수 (메소드,Method)

  • 클래스에 소속된 메소드로 클래스의 기능을 정의하고, 사용하기 위한 용도
  • 같은 클래스에 소속되어 있는 메소드끼리는 조건 없이 호출 가능 그림54

접근 지정자

  • 해당 멤버의 접근성을 설정하는 키워드
  • 멤버 변수, 멤버 함수의 앞에 작성 (지역 변수는 사용 불가능)

  • private, public, protected
  • public : 외부에서 클래스를 통해 접근할 수 있다.
  • private : 외부에서 접근할 수 없으며, 하위 클래스에서도 접근할 수 없다.
  • protected : 외부에서 접근할 수 없으며, 하위 클래스에서는 접근할 수 있다.
  • private는 default 지정자로 접근 지정자를 표기하지 않으면 private로 자동 설정
  • Tip) 멤버 변수의 경우 특별한 경우에만 public을 사용하고, 그렇지 않을 경우는 private, protected를 지향
  • Tip) internal, protected internal, private protected와 같은 접근 지정자도 있다.

접근 지정자의 사용 이유

  • 객체 지향 프로그래밍을 할 때, 클래스에서 최소한의 기능만을 외부로 노출하고, 나머지는 감추는 것을 지향한다. (이를 클래스의 은닉성이라고 함)
  • 현재 클래스 내부에서만 사용하는 기능의 경우 외부로 노출할 필요가 없다

  • 예를 들어, TV를 사용할 때 리모컨을 조작해 TV 채널을 돌리고 즐겁게 TV를 시청하는 것이 사용자의 일이고,
  • 실제로 화면에 어떻게 색이 표현되고, 소리가 어떤 원리로 나는지 몰라도 된다.

  • 그래서 클래스 내에 있는 각 멤버(변수, 메소드)를 필요에 따라 외부에서 사용 가능하도록 하거나 사용할 수 없도록 설정하는 것이 접근지정자의 역할이다

클래스의 이용

  • 클래스도 변수 데이터로 활용 가능 (int, float 등과 동일)
  • 멤버 변수, 지역 변수, 매개 변수, 반환 값 등에 모두 사용 가능 그림55

클래스 객체 생성

  • 클래스는 변수와는 다르게 선언만으로는 사용할 수 없다.
  • new 키워드를 사용해 생성해야 사용 가능
  • .을 사용해 해당 클래스의 멤버(변수, 메소드)에 접근 가능 그림56

null

  • 사전적 의미는 존재하지 않는다는 뜻
  • 초기화하지 않은 클래스의 default 값
  • 가장 빈번하게 Exception을 일으키는 원인
  • Exception : 실행 중에 발생하는 오류

그림57

생성자

  • 객체가 생성될 때 자동으로 호출되는 메소드 (new로 메모리를 할당할 때)
  • 생성자는 클래스 이름과 동일하게 정의 그림58

생성자 메소드 오버로딩

그림59

소멸자

  • 객체가 소멸할 때 자동으로 호출되는 메소드 (가비지 컬렉터가 호출을 담당)
  • 소멸자는 “~클래스 이름”과 같이 정의 그림60

얕은 복사

그림61 그림62

깊은 복사

그림63 그림64

this 키워드

  • 클래스의 변수나 메소드에 접근할 때는 대상이 필요
  • 클래스 내부에서 자기 자신의 변수나 메소드에 접근할 때 this 사용
  • 변수 이름, 메소드 이름만 사용할 경우 default로 this가 자동 지정 그림65

정보 은닉

  • 클래스 외부에서 클래스의 멤버 변수에 직접 접근하지 못하도록 멤버 변수를 private으로 선언하는 것(변수는 데이터를 저장 및 사용하기 때문에 직접 접근할 수 있도록 할 경우 들어가면 안되는 값을 넣어 오류가 발생할 수 있다)

캡슐화

  • 정보은닉으로 인해 클래스 외부에서 접근 불가능한 멤버 변수의 값을 조작할 수 있도록 생성하는 멤버 함수

정보은닉과 캡슐화의 예

그림66

상속 (Inheritance)

  • 유산 상속과 마찬가지로 유산을 물려주는 부모(기반) 클래스가 자신의 재산(public, protected 한정자로 정의된 변수와 메소드)을 유산을 상속 받는 자식(파생) 클래스에게 제공

상속을 하는 이유

  • 여러 클래스에 동일하게 작성되는 내용은 부모 클래스로 작성한 후 자식 클래스가 상속 받아 사용하면 코드 간결화에 도움이 된다.
  • 형식을 통일해 하나의 그룹(배열, 리스트 등)으로 관리할 수 있도록 한다. (업 캐스팅, 다형성 등의 추가적인 기법 필요)

상속의 예

그림67

base 키워드

  • this 키워드가 자기 클래스 내부의 변수, 메소드에 접근할 때 사용하는 키워드라면 부모(기반) 클래스의 변수나 메소드에 접근할 때 사용하는 키워드가 base 그림68

상속 관계에서 생성자와 소멸자 호출 순서

  • Entity(부모)의 생성자 -> Player(자식)의 생성자 -> Player(자식)의 소멸자 -> Entity(부모)의 소멸자 그림69

다형성 (Polymorphism)

  • 다형성은 객체가 여러 가지 다양한 형태를 가지는 것을 뜻한다.
  • 좀 더 정확하게는 상속을 받는 자식 클래스가 다양한 형태를 가지게 된다.

  • 다형성의 첫 번째 과정 [업 캐스팅 (Up-Casting)]
  • 부모 클래스의 참조 변수에 자식 클래스의 객체를 참조하는 것이 가능하다. (부모 클래스의 객체 변수에 자식 클래스 메모리 할당이 가능하다.)
  • 부모 클래스와 자식 클래스 사이에 형 변환이 가능하다.

그림70

  • 부모 클래스의 변수에 자식 클래스 메모리를 할당하는 업캐스팅은 가능하지만 , 자식 클래스 변수에 부모 클래스 메모리에 할당하는 다운캐스팅은 불가능합니다.

  • 참조 변수 형식과 메모리 할당 형식에 따른 사용 가능 멤버 (변수, 메소드) 그림71

업캐스팅을 사용하는 이유?

  • 형식을 통일하기 위해서 사용
  • 플레이어가 다양한 종류의 적을 공격할 때
  • 형식 통일이 필요한 이유는 ?
  • 코드를 간결하게 하고, 코드의 수정을 최소화 하면서도 다양한 경우에 대비하기 위함 입니다.
  • 또한, 형식이 통일되면 배열, 반복문 등을 이용해 동시에 작업을 시키는 것이 수월합니다. 그림72

업캐스팅을 활용한 형식 통일

  • 플레이어가 다양한 종류의 적을 공격할 때 그림73

  • 게임에 존재하는 다양한 적에게 같은 명령을 내릴 때 그림74
  • 게임에 존재하는 다양한 적에게 같은 명령을 내릴 때 그림75

다형성의 두 번째 과정 [메소드 오버라이딩]

  • 메소드 오버라이딩은 업 캐스팅으로 형식이 통일되었을 때 부모 클래스의 메소드가 아닌 자식 클래스의 메소드가 호출되도록 하는 것이다. 그림76 그림77

부모 클래스와 자식 클래스 사이의 형 변환

그림78

  • 앞의 “case 03”과 같은 경우 컴파일할 때는 오류가 발생하지 않고, 프로그램을 실행했을 때 오류가 발생한다.
  • 프로그램 실행 단계에서 형 변환이 가능한지, 형 변환에 성공했는지 확인하는 is와 as 연산자
  • is 연산자 : 객체가 해당 형식에 해당하는지 검사한 후 그 결과를 bool 값으로 반환 (값, 참조 형식 모두 사용 가능)
  • as 연산자 : 형식 변환 연산자와 같은 역할로 형 변환이 가능하면 형 변환을 해서 인스턴스를 반환하고, 형 변환에 실패하면 null을 반환한다. (참조 형식에만 사용 가능)

is, as 연산자 예

그림79

추상 클래스란?

  • 추상 메소드(정의는 있지만 구현된 내용이 없는)를 포함하고 있는 미완성된 클래스
  • 한정자, 반환 형식, 메소드 이름, 매개변수까지만 정의하고, 메소드가 호출되었을 때 어떤 행동을 하는지 내용이 없는 메소드 그림80

추상 메소드란?

  • 한정자, 반환 형식, 메소드 이름, 매개변수까지만 정의하고 메소드가 호출되었을 때 어떤 행동을 하는지 내용이 없는 메소드 그림81

추상 클래스 특징

  • new 연산자를 이용해 클래스 인스턴스를 생성할 수 없고, 추상 클래스를 상속 받은 자식 클래스에서만 구현 후 사용 가능
  • 추상 메소드와 추상 프로퍼티를 정의할 수 있다.

추상 메소드 특징

  • 추상 메소드는 추상 클래스에서만 정의할 수 있다.
  • 추상 메소드의 접근 지정자는 public or protected 중 하나로 정의한다.
  • 추상 메소드를 정의할 때 static, virtual을 사용할 수 없고, abstract 키워드를 사용해서 정의한다.
  • 추상 메소드는 구현 내용이 없고, “이런 메소드를 사용할 것이다.”, “이런 메소드를 구현해야한다!” 라고 자식 클래스에게 구현을 강제하기 때문에 메소드 내용이 없고, 중괄호가 아닌 세미콜론(;)을 사용한다.

추상 클래스, 메소드 사용 이유

  • 클래스를 상속 받는 자식 클래스가 메소드 오버라이딩을 사용할 때 자식 클래스에서 “무조건” 메소드를 구현하도록 하기 위해 사용
  • 앞에서 배운 메소드 오버라이딩의 가상 메소드(virtual)는 자식 클래스에서 메소드를 구현하지 않아도 문제가 없기 때문에 강제성을 주기 위해 사용

추상 클래스의 예

그림82

카테고리:

업데이트:

댓글남기기