경일 메타버스 20220708 14주차 5일 수업내용. Unity를 위한 C# 프로그래밍
C++과는 많은 것이 바뀌고, 그만큼 훨씬 많은 기능을 제공한다.
Array 클래스 :
https://docs.microsoft.com/ko-kr/dotnet/api/system.array?view=netstandard-2.0
배열 사용법 :
https://docs.microsoft.com/ko-kr/dotnet/csharp/programming-guide/arrays/
int[] 등, 타입 뒤에 []을 붙이는 것으로 선언한다.
초기화는 new 타입[]으로 할 수 있고, C++에서처럼 초기화할 수도 있다.
원소 접근은 C++과 같다.
arr[1];
다차원 배열은 바라는 차원 수 만큼 ,을 괄호 안에 넣어 선언한다.
ex) int[,] - 2차원 배열 int [,,,] - 4차원 배열
다차원 배열의 접근은 [ i, j ] 형식으로 한다.
가변 배열(Jagged Array)이란 배열의 배열이다.
타입[][] 의 형식으로 선언한다.
가변 배열은 각 원소가 배열의 주소인 배열이며,
이는 원소인 배열이 비연속적으로 할당되어 있다는 것이다.
매뉴얼에 따르면, 가변 배열이 다차원 배열보다 빠르다.
배열에 대한 조작, 기능 등의 지원은 Array 클래스로 이루어진다.
ex) Array.sort(arr);
// 1차원 배열
int[] arr = new int[5]; // int arr[5]; 와 같다.
// 초기화
arr = new int[5] { 1, 2, 3, 4, 5 };
arr = { 1, 2, 3, 4, 5 };
// 원소 접근
arr[1]; // C++과 같다.
// 인덱서(Indexer)라고 한다.
// 다차원 배열
int[,] arr2 = new int[5, 5]; // int arr[5][5];와 같다.
// 초기화
arr2 = new int[5, 5] { { 1, 2, 3 }, { 4, 5, 6 }};
arr2 = { { 1, 2, 3 }, { 4, 5, 6 } };
// 원소 접근
arr[1, 2]; // 문법에 주의한다. 값은 6이다.
// 가변 배열(Jagged Array) : 배열의 배열
int[][] arr3 = new int[3][];
arr3[0] = new int[2] { 1, 2 };
arr3[1] = new int[4] { 1, 2, 3, 4 };
arr3[2] = new int[3] { 1, 2, 3 };
// C++의 경우, 가변 배열은
int** arr = new int*[3];
arr[0] = new int[2] {1, 2};
arr[1] = new int[4] { 1, 2, 3, 4 };
arr[2] = new int[3] { 1, 2, 3 };
// 원소 접근
arr[1][2]; // 3
C#에서 간접 참조에 좀 더 높은 가독성을 주기 위해 제공하는 것.
가독성을 준다는 것은, 이러한 한정자로 간접 참조의 목적을 알기 쉽게 한다는 것을 의미한다.
ref / in / out 이 있다.
ref
참조로 전달되는 인자를 의미한다.
참조를 목적으로 한다.
int& 과 같다.
ref 한정자를 쓰면 인자가 반드시 초기화 되어 있어야 한다.
초기화를 하지 않으면 컴파일 오류가 난다.
호출할 때 꼭 ref 키워드를 적어야 한다.
예시 코드
// C++
void Swap(int& a, int& b)
{
int temp = a;
a = b;
b = temp;
}
// C#
// ref 한정자를 쓰면 인자가 반드시 초기화 되어 있어야 한다.
// 초기화를 하지 않으면 컴파일 오류가 난다.
void Swap(ref int a, ref int b)
{
int temp = a;
a = b;
b = temp;
}
int a = 10;
int b = 20;
Swap(ref a, ref b); // 호출할 때 꼭 ref 키워드를 적는다.
in
참조로 전달되나, 변경이 되지 않는 인자를 의미한다.
입력을 목적으로 한다.
const int& 와 같다
in 한정자도 인자가 반드시 초기화 되어야 한다.
초기화를 하지 않으면 컴파일 오류가 난다.
호출할 때는 적어주지 않아도 된다.
예시 코드
// C++
void Foo(const int& a, const int& b)
{
// Do Something...
}
// C#
// in 한정자도 인자가 반드시 초기화 되어야 한다.
// 초기화를 하지 않으면 컴파일 오류가 난다.
void Foo(in int a, in int b)
{
// Do Something...
}
out
참조로 전달되는 인자이며, 매개변수를 이용한 출력을 의미한다.
출력을 목적으로 한다.
int& result 와 같다.
out 한정자는 함수가 끝나기 전 반드시 어떤 값이 할당되어야 한다.
호출할 때 꼭 out 키워드를 적어야 한다.
예시 코드
// C++
void Foo(int a, int b, int& result)
{
result = a + b;
}
// C#
// out 한정자는 함수가 끝나기 전 반드시 어떤 값이 할당되어야 한다.
void Foo(int a, int b, out int result)
{
result = a + b;
}
int r;
Foo(10, 20, out r); // 호출할 땐 꼭 out 키워드를 적는다.
C++과 동일하게 필드와 메소드를 작성할 수 있으나,
문법이 다르다.
접근 한정자를 매번 적어야 한다.
접근 한정자의 종류 또한 다르다.
종류 : https://docs.microsoft.com/ko-kr/dotnet/csharp/language-reference/keywords/accessibility-levels
주로 쓰는 접근 한정자
public
protected
private
세미콜론을 안 붙여도 된다.
C++과 C#에서의 클래스 차이 예시 코드
// C++
class Temp
{
public:
Temp()
{
std::cout << "기본 생성자"
}
Temp(int a, int b)
: a(a), b(b)
{
}
Temp(const Temp& other)
: a(other.a), b(other.b)
{
}
void Print()
{
std::cout << a << ", " << b << "\n";
}
private:
int a = 0;
int b = 0;
};
Temp temp = Temp(1, 2); // C++에서의 객체 생성
// C#
public class Temp
{
private int a = 0;
private int b = 0;
public Temp() => Debug.Log("기본 생성자");
// 초기자 리스트가 없다.
public Temp(int a, int b)
{
// C#에는 포인터라는 게 없어서 -> 연산자는 없다.
this.a = a;
this.b = b;
}
// 복사 생성자는 매우 드물게 작성한다.
public Temp(Temp temp)
{
a = temp.a;
b = temp.b;
// 얕은 복사인 경우 아래와 같은 메서드를 이용할 수 있다.
// this = temp.MemberwiseClone();
}
public void Print() => Debug.Log($"{a}, {b}");
}
Temp temp = new Temp(1, 2); // C#에서의 객체 생성
속성은 필드의 확장된 버전이다.
속성 : https://docs.microsoft.com/ko-kr/dotnet/csharp/properties
속성을 이용하면 좀 더 적은 코드로 필드와 관련된 메서드를 작성할 수 있다.
속성 사용 예시 코드
// C++
class Person
{
public:
std::string GetFirstName() const { return _firstName;}
std::string GetSecondName() const { return _secondName; }
std::string GetFullName() const { return _firstName + _secondName; }
void SetFirstName(const std::string& firstName) { _firstName = firstName; }
void SetSecondName(const std::string& secondName) { _secondName = secondName; }
private:
std::string _firstName;
std::string _secondName;
}
// C#
class Person
{
public string FirstName { get; set; }
// 위의 한 줄로 아래의 필드, Getter, Setter 메서드가 생성된 것
// private string _firstName;
// public string GetFirstName() { return _firstName; }
// public string SetFirstName() { _firstName = name; }
public string SecondName { get; set; }
public string FullName
{
get { return $"{FirstName} + {SecondName}"; }
}
}
접근 한정자를 안 써도 된다.
다중 상속이 금지되어 있다.
// C++
class Base { };
// public을 항상 써줘야 함
class Derived : public Base { };
// C#
class Base { }
// 안써도 됨
class Derived : Base { }
class Base1 { }
class Base2 { }
class Derived : Base1, Base2 { } // 컴파일 오류!
값 타입
C# 내장 타입, 구조체 등
스택에 저장된다.
스택에 인스턴스를 생성한다.
참조 타입
클래스, 레퍼런스 모든 컴포넌트, C# 스크립트 등
힙에 저장된다.
힙에 생성된 인스턴스의 주소값을 저장한다.
유니티의 스크립트 실행 순서
스크립트는 복수 있다면 로딩되는 순서대로 임의로 실행된다.
순서를 정하려면
Edit → Project Setting → Script Execution Order
에서 Apply하여 순서를 정할 수 있다.