개발단에 가입하여 베르의 게임 개발 유튜브를 후원해주세요!

 

베르의 게임 개발 유튜브

안녕하세요! 여러분들과 함께 게임 개발을 공부하는 베르입니다! 게임 개발에 도움이 되는 강좌들을 올리는 채널입니다! [투네이션 후원] https://toon.at/donate/637735212761460238 [유니티 어필리에이트

www.youtube.com

안녕하세요! 여러분들과 함께 게임 개발을 공부하는 베르입니다!

이번에는 C#의 리스트에 대해서 알아봅시다.

 

타임라인

0:00 인트로

0:08 리스트란?

0:38 리스트 생성과 데이터 저장

1:55 반복문으로 리스트 안의 데이터 출력하기

3:36 리스트 안의 데이터 찾기

4:20 리스트 안의 데이터 삭제하기

5:35 아웃트로

 

인트로

안녕하세요. 여러분들과 함께 게임 개발을 공부하는 베르입니다.

이번에는 C#의 리스트에 대해서 알아보겠습니다.

리스트란?

먼저 간단하게 이야기해서 리스트는 이름 그대로 하나의 목록처럼 배열과 유사한 방식으로 데이터들을 저장하는 컨테이너입니다.

C# 기초 중에 배열에 대해서 배우신 분들이라면 여러 개의 값들을 묶어서 배열로 저장하는 방법을 기억하고 계실 겁니다.

하지만 배열의 단점은 그 크기가 생성 당시의 크기로 제한이 되기 때문에 배열의 크기를 변경하기 위해서는 배열을 새로 만들어야 합니다.

하지만 리스트는 동적으로 크기가 바뀌기 때문에 그럴 필요가 전혀 없고 메모리가 허용하는 만큼 자동으로 늘어납니다.

리스트 생성과 데이터 저장

먼저 리스트를 만드는 방법을 알아보겠습니다.

리스트를 만들기 위해서는 리스트가 포함되어 있는 System.Collections.Generic 네임스페이스를 using 선언해줘야 합니다.

그 다음 List를 선언하고 뾰족괄호 안에 이 리스트가 저장하고자 하는 데이터 타입을 넣어주면 됩니다.

지금은 int로 적겠습니다.

참고로 이렇게 뾰족괄호 안에 원하는 타입을 넣는 방식은 제네릭이라고 하며 원하는 데이터 타입을 넣을 수 있게 해주는 개념입니다.

이런 제네릭 개념이 없으면 넣고자 하는 데이터 타입에 따라서 IntList, FloatList, StringList 등 같은 기능을 제공하지만 안에 담는 데이터가 다른 클래스들이 무수히 많이 생겨나게 됩니다.

물론 이에 대한 자세한 내용은 추후에 제네릭을 다루는 강좌에서 이야기해보도록 하겠습니다.

이렇게 새로 선언한 리스트는 new 키워드를 사용해서 할당하고 사용하면 됩니다.

그리고 이 리스트에 데이터를 저장하는 방법은 아주 간단합니다.

이런 식으로 Add 함수를 호출하고 매개변수에 넣을 데이터를 입력해주면 됩니다.

이렇게 Add 함수로 넣어준 데이터들은 리스트 안에 넣어준 순서대로 저장됩니다.

이 방법 외에도 Insert 함수를 사용하면 데이터를 맨 끝자리가 아니라 원하는 위치에 넣을 수도 있습니다.

이렇게 첫 번째 매개 변수에는 숫자가 들어갈 위치를 넣고, 두 번째 매개 변수에는 들어갈 데이터를 넣어줍니다.

반복문으로 리스트 안의 데이터 출력하기

앞에서는 리스트 안에 데이터를 넣는 방법을 알아보았으니 이번에는 반복문을 이용해서 리스트를 순회하면서 리스트 안에 들어있는 데이터를 출력해보겠습니다.

먼저 리스트를 순회하는 방법은 크게 두 가지가 있습니다.

먼저 for문을 이용하는 방법입니다.

for문을 이용해서 두 번째 i의 비교 대상에 리스트의 Count, 즉 리스트 안에 들어있는 아이템의 갯수를 넣어주면 for 문은 리스트 안에 들어있는 아이템의 갯수만큼 반복하게 됩니다.

그리고 그 안에서 리스트의 각 방에 접근하여 데이터를 출력하면 이렇게 콘솔창에 표시됩니다.

두 번째 방법은 foreach문을 이용하는 방법입니다.

foreach를 사용하면 따로 방 번호에 해당하는 인덱스 값을 사용하지 않고 리스트를 순회할 수 있습니다.

역시 출력하고 나면 for문으로 순회하며 출력했을 때와 같은 결과를 얻을 수 있습니다.

그럼 for문을 사용해서 하는 리스트 순회와 foreach문을 사용해서 하는 리스트 순회는 어떤 차이가 있으며 어떤 방식이 더 나은지 궁금해하시는 분들이 있을 겁니다.

좋은 자세입니다.

그런 작은 궁금증을 가지고 계속해서 공부하는 자세가 여러분들이 더 나은 프로그래밍 실력을 쌓는 데 큰 발판이 될 겁니다.

먼저 이 두 방식은 성능적인 면에서 현재의 컴퓨터에서는 유의미한 차이를 보이지는 않습니다.

다만, 사용 방식에 따라 다르게 사용하면 되는데, 리스트에 접근하는 방 번호가 유의미하지 않으며 모든 리스트 방을 순차적으로 돌아야 한다면 foreach문을 사용하면 되고, 방 번호가 유의미한 계산에 따라 방을 선택해서 작동해야 한다면 for문을 사용하면 됩니다.

그리고 또 한 가지, 순회하는 도중에 리스트에 데이터를 추가하거나 삭제하는 등의 변동이 발생한다면 for문을 사용하는 것이 좋습니다.

데이터 찾기

그 다음에는 리스트에 데이터를 넣어두고 나중에 필요할 때 원하는 데이터를 꺼내쓰거나 원하는 데이터가 리스트의 어느 위치에 있는지 확인할 수 있어야 합니다.

먼저 Contains 함수를 사용하면 원하는 데이터가 리스트 안에 들어있는지 일일이 반복문을 사용하지 않고도 확인할 수 있습니다.

그리고 원하는 데이터가 리스트의 몇 번째 위치에 있는지 찾는 방법은 IndexOf 함수를 사용하면 됩니다.

참고로 IndexOf 함수를 사용할 때 리스트 안에 들어있지 않은 값을 넣으면 -1을 돌려줍니다.

데이터 삭제하기

리스트에 저장한 데이터는 계속해서 저장해두는 것이 아니라 필요에 따라서 더 이상 필요하지 않은 데이터는 리스트에서 삭제해야 합니다.

그러므로 이번에는 리스트에서 데이터를 삭제하는 방법을 알아보겠습니다.

리스트에서 데이터를 삭제하는 방법 역시 간단합니다.

Remove 함수를 호출하고 매개 변수에 지우고자 하는 값을 넣어주면 됩니다.

다만 이 때 같은 값이 여러 개가 들어있다면 리스트에서 가장 앞에 있는 값만 지워집니다.

그러므로 같은 값들이 모두 삭제되기를 원한다면 RemoveAll 함수를 사용해야 합니다.

다만, RemoveAll 함수는 조금 복잡한 매개 변수를 넣어줘야 하니 이 부분은 적당히 알아두시면 됩니다.

이 외에도 RemoveAt 함수로 리스트의 원하는 위치에 있는 값을 지울 수도 있고 RemoveRange 함수를 사용하면 원하는 위치에서부터 특정한 범위 안에 있는 값을 삭제할 수도 있습니다.

마지막으로 Clear 함수를 사용하면 리스트 안에 있는 모든 데이터를 삭제할 수 있습니다.

아웃트로

이번 영상에서는 C#의 리스트에 대해서 알아보았습니다.

이 외에도 리스트에는 훨씬 많은 기능이 있습니다.

상세한 기능들에 대해서는 강좌 요청이 있다면 추후에 만들어보도록 하겠습니다.

이 강좌는 시청자 여러분들의 시청과 후원으로 제작되었습니다.

이상 베르의 게임 개발 유튜브였습니다. 감사합니다.

 

[유니티 어필리에이트 프로그램]

아래의 링크를 통해 에셋을 구매하시거나 유니티를 구독하시면 수익의 일부가 베르에게 수수료로 지급되어 채널의 운영에 도움이 됩니다.

 

에셋스토어

여러분의 작업에 필요한 베스트 에셋을 찾아보세요. 유니티 에셋스토어가 2D, 3D 모델, SDK, 템플릿, 툴 등 여러분의 콘텐츠 제작에 날개를 달아줄 다양한 에셋을 제공합니다.

assetstore.unity.com

 

Easy 2D, 3D, VR, & AR software for cross-platform development of games and mobile apps. - Unity Store

Have a 2D, 3D, VR, or AR project that needs cross-platform functionality? We can help. Take a look at the easy-to-use Unity Plus real-time dev platform!

store.unity.com

 

Create 2D & 3D Experiences With Unity's Game Engine | Unity Pro - Unity Store

Unity Pro software is a real-time 3D platform for teams who want to design cross-platform, 2D, 3D, VR, AR & mobile experiences with a full suite of advanced tools.

store.unity.com

[투네이션]

 

-

 

toon.at

[Patreon]

 

WER's GAME DEVELOP CHANNEL님이 Game making class videos 창작 중 | Patreon

WER's GAME DEVELOP CHANNEL의 후원자가 되어보세요. 아티스트와 크리에이터를 위한 세계 최대의 멤버십 플랫폼에서 멤버십 전용 콘텐츠와 체험을 즐길 수 있습니다.

www.patreon.com

[디스코드 채널]

 

Join the 베르의 게임 개발 채널 Discord Server!

Check out the 베르의 게임 개발 채널 community on Discord - hang out with 399 other members and enjoy free voice and text chat.

discord.com

 

반응형

개발단에 가입하여 베르의 게임 개발 유튜브를 후원해주세요! 

 

베르의 게임 개발 유튜브

안녕하세요! 여러분들과 함께 게임 개발을 공부하는 베르입니다! 게임 개발에 도움이 되는 강좌들을 올리는 채널입니다! [투네이션 후원] https://toon.at/donate/637735212761460238 [유니티 어필리에이트

www.youtube.com

 

안녕하세요! 여러분들과 함께 게임 개발을 공부하는 베르입니다!

이번에는 C#의 enum에 대해서 알아봅시다.

 

타임라인

0:00 인트로

0:40 enum을 사용하지 않을 때

1:55 열거형 enum

3:30 아웃트로

 

[참고자료]

마이크로소프트 C# 공식 도큐먼트 - https://docs.microsoft.com/ko-kr/dotnet/csharp/language-reference/builtin-types/enum

예제로 배우는 C# 프로그래밍 - https://www.csharpstudy.com/CSharp/CSharp-enum.aspx

 

[예제]

https://drive.google.com/file/d/1E1MBAEJVS3iQ8u8OMT-_Z3BZv2SZ9j5E/view?usp=sharing

 

스크립트

인트로

안녕하세요. 여러분들과 함께 게임 개발을 공부하는 베르입니다.

이번에는 C#의 enum에 대해서 알아보도록 하겠습니다.

보통 인간은 문자와 기호 그리고 숫자를 이용하지만 컴퓨터는 모든 것을 0과 1로 된 숫자로 받아들입니다.

그렇기 때문에 인간이 알아보기 쉽게 문자열로 만들면 프로그램이 느려지고 컴퓨터가 알아보기 쉽게 숫자로 만들면 인간이 알아보기 어려워집니다.

이것을 해결하기 위한 방법의 하나가 바로 enum, 즉 열거형입니다.

열거형에 대해서 알아보기 위해서 먼저 비주얼 스튜디오를 실행하고 빈 C# 프로젝트를 생성해줍니다.

enum을 사용하지 않을 때

먼저 enum을 사용하지 않고 프로그램을 만들 때는 어떻게 되는지 알아봅시다.

프로그램은 아주 간단한 형태라고 해도 여러 가지의 상태나 타입을 가지게 되는 경우가 많습니다.

지금은 간단한 예시로 두 개의 숫자와 계산 타입을 받아서 결과 값을 돌려주는 함수를 만들어보겠습니다.

물론 실제 프로그래밍에서는 이렇게 Calculate 함수 하나만 만들고 타입에 따라서 계산 결과를 돌려주는 것보다는 각 계산 방식에 따라서 함수를 따로 만드는 방식을 채택하겠지만 지금은 예시를 보여드리기 위함이니 이렇게 만들도록 하겠습니다.

먼저 계산 타입을 int 형으로 받는 방식은 이렇게 구현됩니다.

이런 int 타입으로 구현 된 방식의 경우에는 각 숫자가 어떤 계산 타입을 말하는 것인지 알기 어려운 문제가 있음을 한 눈에 알 수 있습니다.

그래서 어떤 숫자가 어떤 계산 방식을 뜻하는지 함수 사용자에게 알리기 위해서는 많은 양의 주석을 달 수 밖에 없습니다.

그 다음 방법은 타입을 문자열로 받는 방식입니다.

이렇게 문자열로 타입을 받게 되면 사람이 코드를 읽기는 쉬워지지만, int 타입과 마찬가지로 어떤 문자열이 어떤 타입을 나타내는지 추가로 주석을 달아서 알려줘야 하며, 더 큰 문제는 타입을 입력할 때 오타가 발생할 수 있다는 점입니다.

열거형 enum

이렇게 타입이나 상태를 정의할 때 int나 string을 사용하면 발생하는 문제들을 살펴보았습니다.

이번에는 이 영상의 주제인 enum으로 계산 타입을 만들어보겠습니다.

enum을 만들 때는 이렇게 해당 열거형의 이름을 적고 중괄호 안에 각 타입의 이름을 적어주면 됩니다.

이 때 이름은 문자열로 적듯이 원하는 이름을 자유롭게 적어주면 됩니다.

그리고 이렇게 선언된 열거형 키워드들은 각각 하나의 정수에 대응되는데 추가로 값을 대응시켜주지 않으면 배열처럼 0부터 차례대로 숫자가 매겨집니다.

이렇게 각 키워드마다 배열처럼 숫자가 매겨지는 점을 이용해서 enum을 int 타입으로 바꿔서 배열에 접근하는 방식으로 사용할 수 있습니다.

물론 반대로 int 타입을 enum 형식으로 바꿀 수도 있습니다.

그리고 키워드들이 다른 값을 가지기를 원하면 이런 식으로 대입시켜주면 되고 대입해준 키워드부터는 대입해준 값을 기반으로 숫자가 올라갑니다.

추가로 이렇게 키워드에 값을 대입해주는 방식을 이용하면 서로 다른 키워드가 같은 값을 가지게 만들 수도 있습니다.

이렇게 만든 enum 타입으로 다시 Calculate 함수를 만들어보면 이런 방식으로 구현됩니다.

앞에서 int나 string으로 만든 함수와 별 차이는 없어보이지만, 실제로 사용했을 때는 별도의 주석이나 설명없이도 어떤 계산 타입이 존재하며 어떤 값을 넣어줘야 하는지 명확하게 알 수 있습니다.

이런 방식 외에도 아래의 참고자료 링크를 보시면 Flags 어트리뷰트를 이용해 비트 연산을 하는 응용법도 있습니다.

비트연산과 관련된 내용은 지금 영상 오른쪽 상단에 표시되는 영상 링크를 통해서 보실 수 있습니다.

아웃트로

이번 영상에서는 C#의 enum에 대해서 알아보았습니다.

이 강좌는 시청자 여러분들의 시청과 후원으로 제작되었습니다.

이상 베르의 게임 개발 유튜브였습니다. 감사합니다.

 

[유니티 어필리에이트 프로그램]

아래의 링크를 통해 에셋을 구매하시거나 유니티를 구독하시면 수익의 일부가 베르에게 수수료로 지급되어 채널의 운영에 도움이 됩니다.

 

에셋스토어

여러분의 작업에 필요한 베스트 에셋을 찾아보세요. 유니티 에셋스토어가 2D, 3D 모델, SDK, 템플릿, 툴 등 여러분의 콘텐츠 제작에 날개를 달아줄 다양한 에셋을 제공합니다.

assetstore.unity.com

 

Easy 2D, 3D, VR, & AR software for cross-platform development of games and mobile apps. - Unity Store

Have a 2D, 3D, VR, or AR project that needs cross-platform functionality? We can help. Take a look at the easy-to-use Unity Plus real-time dev platform!

store.unity.com

 

Create 2D & 3D Experiences With Unity's Game Engine | Unity Pro - Unity Store

Unity Pro software is a real-time 3D platform for teams who want to design cross-platform, 2D, 3D, VR, AR & mobile experiences with a full suite of advanced tools.

store.unity.com

[투네이션]

 

-

 

toon.at

[Patreon]

 

WER's GAME DEVELOP CHANNEL님이 Game making class videos 창작 중 | Patreon

WER's GAME DEVELOP CHANNEL의 후원자가 되어보세요. 아티스트와 크리에이터를 위한 세계 최대의 멤버십 플랫폼에서 멤버십 전용 콘텐츠와 체험을 즐길 수 있습니다.

www.patreon.com

[디스코드 채널]

 

Join the 베르의 게임 개발 채널 Discord Server!

Check out the 베르의 게임 개발 채널 community on Discord - hang out with 399 other members and enjoy free voice and text chat.

discord.com

 

반응형

foreach 

배열과 컬렉션를 위한 반복문

 

기본적인 for문

 

int[] numbers = new int[10] { 0, 1, 2, 3, 4, 5, 6, 7, 8, 9 };

for (int i = 0; i < numbers.Length; i++)

{

    Console.Write(numbers[i] + " ");

}

Console.WriteLine("");

 

C# 프로그래밍에서 기본적으로 사용되는 배열 반복문은 위의 코드와 같이 for문을 사용한다.. C#의 배열은 기본적으로 배열 안에 있는 요소의 수를 Length 프로퍼티로 알려주기 때문에 C++처럼 for문을 사용하다가 Index Out Of Range Exception이 발생할 가능성은 적다.

 

List<int> numList = new List<int>() { 0, 1, 2, 3, 4, 5, 6, 7, 8, 9 };

for (int i = 0; i < numList.Count; i++)

{

    Console.Write(numbers[i] + " ");

}

Console.WriteLine("");

 

for문을 이용한 리스트의 순회 역시 배열의 순회와 거의 같은 형태를 취하기 때문에 사용에 큰 어려움은 없다고 느낄 수 있다.

 

Dictionary<int, int> numDictionary = new Dictionary<int, int>() { { 0, 0 }, { 1, 1 }, { 2, 2 } };

for(var enumerator = numDictionary.GetEnumerator(); enumerator.MoveNext(); )

{

    Console.Write(enumerator.Current.Key + ":" + enumerator.Current.Value + " ");

}

Console.WriteLine("");

 

하지만 for문을 사용해서 딕셔너리를 순회하려고 하면 위의 코드와 같이 열거자를 활용해서 코드를 작성해야하기 때문에 코드가 길어지고 열거자에 대해서 아직 익숙하지 않은 개발자라면 쉽게 사용하기가 어렵다.

 

 

foreach문을 사용한 컬렉션 순회

 

그렇다면 이제 foreach문을 사용한 예시 코드를 보자.

 

int[] numbers = new int[10] { 01234, 56789 };

foreach(var num in numbers)

{

    Console.Write(num + " ");

}

Console.WriteLine("");

 

List<int> numList = new List<int>() { 0123456789 };

foreach (var num in numList)

{

    Console.Write(num + " ");

}

Console.WriteLine("");

 

Dictionary<intint> numDictionary = new Dictionary<intint>() { { 0}, { 11 }, { 22 } };

foreach (var num in numDictionary)

{

    Console.Write(num.Key + ":" + num.Value + " ");

}

Console.WriteLine("");

 

이번에는 배열, 리스트, 딕셔너리의 예시를 한꺼번에 작성했다. foreach문을 사용해서 딕셔너리를 순회하면 열거자를 사용할 때보다 훨씬 코드가 짧아지고 리스트나 배열에서도 조금 더 작성이 편해지는 것을 알 수 있다.

 

List<int> numList = new List<int>() { 0123456789 };

foreach (var num in numList)

{

    Console.Write(num + " ");

}

Console.WriteLine("");

 

간단하게 리스트를 순회하는 foreach문을 예시로 들어서 설명해보자면 foreach (var 임시변수 in 순회하고자 하는 컬렉션)으로 매 반복마다 순회하고자 하는 컬렉션의 요소를 받아와서 사용하는 방식이다. foreach는 컬렉션의 순회가 끝나면 자동으로 반복을 중지하기 때문에 Index Out Of Range Exception이 발생할 염려가 없다.

 

 

foreach문의 다차원 배열 순회

 

int[,] array = new int[2, 3]

{

    { 0, 1, 2 },

    { 3, 4, 5 },

};

 

for (int i = 0; i < 2; i++)

{

    for (int j = 0; j < 3; j++)

    {

        Console.WriteLine(string.Format("multiLayerArray[{0},{1}] :: {2}", i, j, array[i, j]));

    }

}

 

foreach (var num in array)

{

    Console.WriteLine(num);

}

 

foreach문을 사용하면 다차원 형태의 배열 역시 순회가 손쉽게 가능하다. for문을 이용해서 다차원 배열을 순회하려면 n차원에 대해서 n중 for문을 구현해야하지만 foreach문을 이용하면 단 하나의 for문으로 다차원 배열의 순회가 가능해진다.

 

하지만 이것은 각각의 장단점이 명확하게 갈린다. 다차원 배열의 경우, foreach문으로 순회하면 코드가 간단해지는 장점이 있지만, for문을 통한 다차원 배열의 순회처럼 각각의 인덱스에 대한 처리가 어려워진다.

 

 

foreach를 활용한 enum 순회

 

public enum DayOfWeek { Monday = 1, Tuesday, Wednesday, Thursday, Friday, Saturday, Sunday }

 

foreach (int dow in Enum.GetValues(typeof(DayOfWeek)))

{

    Console.WriteLine(string.Format("{0}번째 요일", dow));

 

}

 

foreach (string dow in Enum.GetNames(typeof(DayOfWeek)))

{

    Console.WriteLine(dow);

}

 

foreach와 Enum 클래스를 이용해서 enum에 대한 순회역시 가능하다.

 

[유니티 어필리에이트 프로그램]

아래의 링크를 통해 에셋을 구매하시거나 유니티를 구독하시면 수익의 일부가 베르에게 수수료로 지급되어 채널의 운영에 도움이 됩니다.

 

에셋스토어

여러분의 작업에 필요한 베스트 에셋을 찾아보세요. 유니티 에셋스토어가 2D, 3D 모델, SDK, 템플릿, 툴 등 여러분의 콘텐츠 제작에 날개를 달아줄 다양한 에셋을 제공합니다.

assetstore.unity.com

 

Easy 2D, 3D, VR, & AR software for cross-platform development of games and mobile apps. - Unity Store

Have a 2D, 3D, VR, or AR project that needs cross-platform functionality? We can help. Take a look at the easy-to-use Unity Plus real-time dev platform!

store.unity.com

 

Create 2D & 3D Experiences With Unity's Game Engine | Unity Pro - Unity Store

Unity Pro software is a real-time 3D platform for teams who want to design cross-platform, 2D, 3D, VR, AR & mobile experiences with a full suite of advanced tools.

store.unity.com

[투네이션]

 

-

 

toon.at

[Patreon]

 

WER's GAME DEVELOP CHANNEL님이 Game making class videos 창작 중 | Patreon

WER's GAME DEVELOP CHANNEL의 후원자가 되어보세요. 아티스트와 크리에이터를 위한 세계 최대의 멤버십 플랫폼에서 멤버십 전용 콘텐츠와 체험을 즐길 수 있습니다.

www.patreon.com

[디스코드 채널]

 

Join the 베르의 게임 개발 채널 Discord Server!

Check out the 베르의 게임 개발 채널 community on Discord - hang out with 399 other members and enjoy free voice and text chat.

discord.com

 

 

반응형

Thread 

스레드 생성 시 반복문의 인덱스를 매개변수로 받을 때

 

스레드(Thread)를 생성할 때, 반복문으로 여러 개의 스레드를 생성하면서 그 반복문의 인덱스를 매개변수로 전달하는 방법을 쓸 때가 있다.

 

class ThreadTestProgram

{

    public static int DeviceNum = 10;

 

    public static void Main(string[] args)

    {

        for (int i = 0; i < DeviceNum; i++)

        {

            new Thread(() => Run(i)).Start();

        }

    }

 

    public static void Run(int idx)

    {

        // 디바이스 인덱스에 따라서 스레드 별로 각 디바이스와 연결하는 작업...

        Console.WriteLine(idx);

    }

}

 

위의 예시 코드가 바로 그것이다. 여러 개의 디바이스에 연결해서 스레드로 작업을 처리해야 할 때의 코드인데, 스레드 함수에서는 반복문에서 디바이스의 인덱스를 전달받아서 연결하도록 설계된 코드이다.

 

물론 스레드이기 때문에 실행 순서 자체는 보장할 수 없지만, 적어도 각 스레드가 매개변수의 값으로 0, 1, 2, 3, 4, 5, 6, 7, 8, 9를 전달받는 것을 기대하고 설계된 코드라고 볼 수 있다.

 

 

하지만 실행결과를 보면 각 스레드가 전달받은 매개변수 값은 1, 2, 3, 4, 5, 5, 6, 8, 8, 10으로 0, 7, 9를 전달받은 스레드는 없고 5와 8을 전달받은 스레드는 두 개씩 있는 엉망진창인 상태인 것을 볼 수 있다.

 

이 상황이 의미하는 것은 스레드의 매개변수로 넣은 반복문의 인덱스 값이 스레드가 시작되기 전에 변경되면 스레드의 매개변수 값 역시 영향을 받는다는 것이다.

 

// int i = 0 -> 반복문에 사용될 인덱스 값 설정

for(int i = 0; i < DeviceNum; i++)

{// i < DeviceNum -> 인덱스 값이 반복문 내의 코드 블럭을 실행하기에 유효한지 검사

    new Thread(() => Run(i)).Start(); // 스레드 생성 

    // i 값이 증가하기 전에 스레드가 시작되면 원래 값이 들어간다.

}// i++ 값 증가 // i 값이 증가한 이후에 스레드가 시작되면 i + 1 값이 들어간다.

 

각 코드 진행 상황에 대한 해설을 달자면 위와 같다. i값이 증가한 이후에 스레드가 시작되는 것이 문제로 스레드가 시작되기 전까지 전달되는 값이 변하지 않을 것에 대한 보장이 필요한 상태이다.

 

이를 위해서 코드를 다음과 같이 변경해보자.

 

class ThreadTestProgram

{

    public static int DeviceNum = 10;

 

    public static void Main(string[] args)

    {

        for (int i = 0; i < DeviceNum; i++)

        {

            int idx = i; // i 값이 바뀌어도 상관없도록 임시 변수에 값을 전달하여 스레드의 매개 변수로 사용

            new Thread(() => Run(idx)).Start();

        }

    }

 

    public static void Run(int idx)

    {

        // 디바이스 인덱스에 따라서 스레드 별로 각 디바이스와 연결하는 작업...

        Console.WriteLine(idx);

    }

}

 

위의 임시 코드처럼 i의 값을 임시 변수에 전달해서 스레드에 매개변수로 전달하면 i값이 증가해도 idx의 값은 증가하지 않기 때문에 스레드가 실행될 때까지 값이 변조되지 않을 것이다.

 

 

실제로 코드를 컴파일해보면 실행순서는 섞여있지만 각 스레드가 디바이스 인덱스로 0, 1, 2, 3, 4, 5, 6, 7, 8, 9를 받은 것을 확인할 수 있다.

 

[유니티 어필리에이트 프로그램]

아래의 링크를 통해 에셋을 구매하시거나 유니티를 구독하시면 수익의 일부가 베르에게 수수료로 지급되어 채널의 운영에 도움이 됩니다.

 

에셋스토어

여러분의 작업에 필요한 베스트 에셋을 찾아보세요. 유니티 에셋스토어가 2D, 3D 모델, SDK, 템플릿, 툴 등 여러분의 콘텐츠 제작에 날개를 달아줄 다양한 에셋을 제공합니다.

assetstore.unity.com

 

Easy 2D, 3D, VR, & AR software for cross-platform development of games and mobile apps. - Unity Store

Have a 2D, 3D, VR, or AR project that needs cross-platform functionality? We can help. Take a look at the easy-to-use Unity Plus real-time dev platform!

store.unity.com

 

Create 2D & 3D Experiences With Unity's Game Engine | Unity Pro - Unity Store

Unity Pro software is a real-time 3D platform for teams who want to design cross-platform, 2D, 3D, VR, AR & mobile experiences with a full suite of advanced tools.

store.unity.com

[투네이션]

 

-

 

toon.at

[Patreon]

 

WER's GAME DEVELOP CHANNEL님이 Game making class videos 창작 중 | Patreon

WER's GAME DEVELOP CHANNEL의 후원자가 되어보세요. 아티스트와 크리에이터를 위한 세계 최대의 멤버십 플랫폼에서 멤버십 전용 콘텐츠와 체험을 즐길 수 있습니다.

www.patreon.com

[디스코드 채널]

 

Join the 베르의 게임 개발 채널 Discord Server!

Check out the 베르의 게임 개발 채널 community on Discord - hang out with 399 other members and enjoy free voice and text chat.

discord.com

 

반응형

Thread 

여러 작업을 동시 처리하기

 

일반적으로 우리가 사용하는 운영체제(Operation System, OS)은 멀티 태스크를 지원한다. 그 덕분에 우리는 구글에서 자료를 찾으면서, 유튜브에서 강좌를 듣고, 동시에 비주얼 스튜디오에서 작업을 할 수 있으며 그와 동시에 오디오 재생 프로그램을 통해서 음악을 들을 수 있다. 이때 구글과 유튜브에 접속할 수 있게 해주는 브라우저, 코드 작업을 하는 비주얼 스튜디오, 음악을 재생한느 오디오 재생 프로그램이 각각 하나의 프로세스(Process)이다.

 

또 여기서 이 프로세스는 하나 이상의 스레드(Thread)로 이루어진다. 스레드는 프로세스를 여러 개의 조각으로 나눈 것으로, 한 OS에서 여러 프로세스가 작업하는 것처럼, 한 프로세스에서 여러 스레드가 동시에 작업을 처리할 수 있게 해준다. 방금 앞에서 든 예시 중에 오디오 재생 프로그램을 예시로 들자면, 오디오 프로그램은 하나의 프로세스으로, 그 안에서 여러 스레드로 나뉘어서 한 스레드는 음악을 재생하고, 또 다른 스레드는 가사를 보여주면서 음악 재생 시간에 맞춰서 싱크를 맞추는 등의 방식으로 동시에 여러 가지 작업을 동시에 처리하는 것이다.

 

 

스레드 생성/시작하기

 

그럼 이 스레드를 사용하기 위한 방법을 차근차근 배워보자.

 

using System.Threading;

 

스레드에 관련된 기능들은 System.Threading 네임스페이스에 포함되어 있다. System.Threading.* 처럼 일일이 네임스페이스를 입력해서 코드를 작성해줄 수도 있지만 가독성 문제와 작업 효율성을 위해서 using 선언을 해주자.

 

using System;using System.Threading;
namespace ThreadTest
{
    class ThreadTestProgram
    {

        public static void Main(string[] args)

        {
            Run(0);
            Run(1);
        }

        public static void Run(int idx)
        {

            Console.WriteLine(string.Format("Run {0} Start"idx));

            for (int i = 0; i < 10; i++)
            {
                Console.WriteLine(string.Format("Run {0} :: {1}", idx, i));
            }
            Console.WriteLine(string.Format("Run {0} End", idx));
        }
    }
}

 

우선 스레드를 사용하지 않는 경우의 코드를 먼저 확인해보자. 위의 코드는 스레드를 전혀 사용하지 않고 Run() 함수가 두 번 연속 호출된다. 

 

 

이렇게 스레드를 사용하지 않고 Run() 함수를 두 번 호출하면 모두가 알다시피 코드는 순차적으로 진행해서 첫 번째 Run(0) 함수가 완전히 끝난 후에야 두 번째 Run(1) 함수가 동작한다.

 

using System;

using System.Threading;

namespace ThreadTest
{
    class ThreadTestProgram
    {

        public static void Main(string[] args)

        {
            Thread thread = new Thread(() => Run(0));

 

            thread.Start();

            Run(1);

        }

        public static void Run(int idx)
        {
            Console.WriteLine(string.Format("Run {0} Start", idx));
            for (int i = 0; i < 100; i++)
            {
                Console.WriteLine(string.Format("Run {0} :: {1}", idx, i));
            }
            Console.WriteLine(string.Format("Run {0} End", idx));
        }
    }
}

 

이번에는 스레드를 생성해서 첫 번째 Run(0) 함수를 스레드로 호출하게 했다. 그리고 반복문 10회로는 동시 실행을 판별하기 어려워서 반복 횟수를 100회로 늘렸다.

 

 

스레드를 사용한 후의 실행결과는 어느 함수가 끝나기 전에 두 함수가 동시에 진행되고 있음을 충분히 알 수 있다.

 

Thread thread = new Thread(() => Run(0));

 

thread.Start();

 

스레드를 사용하는 방법은 간단하게 Thread 객체를 생성하고 생성자의 매개변수로 스레드로 돌리고자 하는 함수를 넣어준 뒤 Start() 함수를 호출하면 된다. 스레드를 생성하기만 하고 Start() 함수를 호출하지 않으면 그 스레드는 동작하지 않는다.

 

 

스레드 양보하기

 

위의 스레드 실행 예시 이미지를 보면 스레드가 몇 번의 연산을 처리하고 잠시 다른 스레드에 처리 시간을 넘겨주고 다시 돌려받는 것을 알 수 있다. 스레드 프로그래밍에서는 이런 CPU 점유 상태를 다른 스레드에 언제 얼마동안 양보할 지를 알리는 함수가 있는데 이것이 바로 Thread.Sleep() 함수다.

 

Thread.Sleep(10);

 

Thread.Sleep() 함수는 해당 함수를 호출한 스레드가 매개변수의 시간만큼 쉬면서 다른 스레드에 처리 우선권을 양보하게 만든다. 매개변수의 시간 단위는 밀리세컨드(Milisecond)로 1000분의 1초에 해당한다. 즉 위 코드에 적힌 시간으로는 0.001초 동안 다른 스레드에 처리 우선권을 양보한다는 의미이다.

 

using System;

using System.Threading;

namespace ThreadTest
{
    class ThreadTestProgram
    {

        public static void Main(string[] args)

        {
            Thread thread0 = new Thread(() => Run(0));

 

            thread0.Start();
            Thread thread1 = new Thread(() => Run(1));

 

            thread1.Start();
        }

        public static void Run(int idx)
        {
            Console.WriteLine(string.Format("Run {0} Start", idx));
            for (int i = 0; i < 100; i++)
            {
                Console.WriteLine(string.Format("Run {0} :: {1}", idx, i));
                Thread.Sleep(10);
            }
            Console.WriteLine(string.Format("Run {0} End", idx));
        }
    }
}

 

이번에는 Run(0)와 Run(1) 함수를 모두 스레드로 호출했으며 반복문 중간에 Sleep() 함수를 추가했다.

 

 

이번 실행결과를 보면 Sleep() 함수를 사용하지 않을 때와는 다르게 허용된 시간에 최대한 몰아서 처리하지 않고 필요한 계산만 처리한 뒤에 바로 다른 스레드에게 처리 우선권을 넘기는 것을 확인할 수 있다.

 

 

 

 

스레드 중단하기

 

thread.Abort();

thread.Join();

 

작동 중인 스레드를 중지하는 방법은 두 가지가 있는데 Abort() 함수와 Join() 함수가 그것이다. 이 두 함수의 차이는 다음과 같다.

 

Abort() :: 함수의 종료를 보장하지 않고 어느 시점이던지 상관 없이 도중에 강제로 중단시킨다.

Join() :: 함수의 종료를 보장하며 스레드가 동작시키는 중인 함수의 끝에 도달하기를 기다린 다음에 스레드를 닫는다.

 

using System;

using System.Threading;
namespace ThreadTest
{
    class ThreadTestProgram
    {

        public static void Main(string[] args)

        {
            Thread thread0 = new Thread(() => Run(0));

 

            thread0.Start();
            Thread.Sleep(100);

 

            thread0.Abort();
            Thread thread1 = new Thread(() => Run(1));

 

            thread1.Start();
            Thread.Sleep(100);

 

            thread1.Join();
        }

        public static void Run(int idx)
        {
            Console.WriteLine(string.Format("Run {0} Start", idx));
            for (int i = 0; i < 100; i++)
            {
                Console.WriteLine(string.Format("Run {0} :: {1}", idx, i));
                Thread.Sleep(10);
            }
            Console.WriteLine(string.Format("Run {0} End", idx));
        }
    }
}

 

thread0은 Abort() 시키고 thread1은 Join() 시키는 코드를 작성한다음 컴파일 해보자.

 

 

Run(0)는 반복문이 동작하던 도중에 중단되고, Run(1)은 End까지 무사히 호출되고 종료된 것을 확인할 수 있다.

 

위듸 예시를 통해 알 수 있듯이 Abort() 함수의 경우에는 스레드를 작동 도중에 강제로 종료하기 때문에 스레드 강제 종료가 시스템에 심각한 영향을 끼치지 않는다는 보장이 있을 때만 사용하는 것이 좋다.

 

class ThreadTestProgram

{

    public static void Main(string[] args)

    {

        Thread thread0 = new Thread(() => Run(0));

        thread0.Start();

        Thread.Sleep(100);

        thread0.Abort();

    }

 

    public static void Run(int idx)

    {

        try

        {

            int runIdx = idx;

            Console.WriteLine(string.Format("Run {0} Start", runIdx));

            for (int i = 0; i < 100; i++)

            {

                Console.WriteLine(string.Format("Run {0} :: {1}", runIdx, i));

                Thread.Sleep(10);

            }

            Console.WriteLine(string.Format("Run {0} End", runIdx));

        }

        catch (Exception e)

        {

            Console.WriteLine(e);

        }

    }

}

 

스레드를 Abort() 함수로 강제 종료할 때 해당 스레드 함수에서는 System.Threading.ThreadAbortException이라는 예외를 발생시킨다. 만약 스레드를 Abort() 시켰을 때, 리소스 정리 등의 뒤처리 작업이 필요한 경우라면 반드시 해당 스레드 함수에서 발생하는 ThreadAbortException 예외를 받아서 정리 작업을 진행하는 것이 좋다.

 

 

스레드 동기화(Thread Synchronization)

 

여러 개의 스레드를 두고 작동하는 프로그램의 경우에, 여러 스레드가 자원이나 변수 등을 공유하는 경우가 많다. 다음의 예시를 보자.

 

class ThreadTestProgram

{

    public class Villige

    {

        public int population =1000

            

        public void AddVillager()

        {

            population++;

 

           for(int i = 0; i < population; i++)

            {

               for(int j = 0; j < population; j++)

                {

 

                }

            }

            // 추가된 주민에게 주민번호 주기

           Console.WriteLine(string.Format("새 주민의 주민번호 :: {0}", population));

        }

    }

 

    public static void Main(string[] args)

    {

        Villige manager = new Villige();

        for(int i = 0; i < 10; i++)

        {

            new Thread(new ThreadStart(manager.AddVillager)).Start();

        }

    }

}

 

작은 마을을 키우는 게임을 만든다고 가정했을 때, 마을에 새로운 마을 주민이 태어나거나 새로 들어오면 인구 수를 늘려주고 몇 가지 처리를 한 뒤에 주민번호를 매겨주는 AddVillager() 함수를 구현했다. 그리고 주민번호는 고유한 번호이기 때문에 각 주민 마다 번호가 중복되어서는 안된다고 가정해보자. 이 때 마을 주민이 동시에 추가될 수도 있기 때문에 스레드 처리를 한다.

 

그런데 플레이 도중에 마을에 10명의 주민이 동시에 추가되었다고 해보자. 그러면 현재까지 1000명의 주민이 있었으니 그 뒤에 추가되는 주민들의 번호는 1001, 1002, 1003, ..., 1009, 1010이 되기를 기대할 것이다.

 

 

하지만 실행결과는 새 주민들의 주민번호가 중복되어서 발급되어 버렸다. 이러한 문제를 스레드 세이프 하지 않다(Not thread-safe)라고 하는데 이 문제를 해결하기 위해서 필요한 것이 바로 스레드 동기화이다. 스레드 동기화는 하나의 공용된 자원이나 변수에 여러 개의 스레드가 접근할 때, 스레드들이 순서를 지켜서 사용하고 다른 스레드가 사용 중일 때는 사용하지 못하게 만드는 것이다.

 

class ThreadTestProgram

{

    public class Vilige

    {

        public int population = 1000;

 

        public object populationLock = new object();

 

        public void AddHuman()

        {

            lock (populationLock)

            {

                population++;

 

                for (int i = 0; i < population; i++)

                {

                    for (int j = 0; j < population; j++)

                    {

 

                    }

                }

                // 추가된 주민에게 주민번호 주기

                Console.WriteLine(string.Format("새 주민의 주민번호 :: {0}", population));

            }

        }

    }

 

    public static void Main(string[] args)

    {

        Vilige manager = new Vilige();

        for(int i = 0; i < 10; i++)

        {

            new Thread(new ThreadStart(manager.AddHuman)).Start();

        }

    }

}

 

스레드를 동기화하는 방법은 lock을 사용사는 것이다. 스레드 락을 하기 위한 객체를 하나 만들어서 lock()을 해주면 lock() { } 으로 묶어준 블럭이 한 스레드에서 실행되는 동안에는 같은 객체의 lock으로 묶인 스레드는 멈춘 상태로 해당 코드를 진행하지 못하게 된다.

 

 

스레드를 lock() 함수로 동기화하여 실행하면 새로 들어온 주민들의 주민번호가 겹치지 않고 정상적으로 매겨지게 된다.

 

이런 스레드 동기화에도 단점은 있는데 스레드 동기화되는 부분은 동시 처리가 안되고 한 스레드씩 작업을 진행하기 때문에 프로그램의 속도가 느려질 수 있다.

 

 

그리고 스레드의 동기화 구조가 복잡한 경우라면, 위의 이미지처럼 두 개의 스레드가 두 자원을 사용하려고 할 때, 스레드 1이 자원 1을 사용하며 자원 2가 풀리기를 기다리고 있고 스레드 2가 자원 2를 사용하며 자원 1이 풀리기를 기다려서 두 스레드가 멈춰버리는 데드락(Dead lock, 교착상태)이 발생할 수도 있다.

 

이렇게 스레드는 동시 처리를 하기에 유용한 방법이지만, 호출 순서를 보장할 수 없고 디버깅이 어려운 구조이기 때문에 잘못 사용할 경우 해결하기 어려운 문제를 발생시키기 쉽다. 그러므로 스레드를 사용할 때는 조심해서 사용해야만 한다.

 

[유니티 어필리에이트 프로그램]

아래의 링크를 통해 에셋을 구매하시거나 유니티를 구독하시면 수익의 일부가 베르에게 수수료로 지급되어 채널의 운영에 도움이 됩니다.

 

에셋스토어

여러분의 작업에 필요한 베스트 에셋을 찾아보세요. 유니티 에셋스토어가 2D, 3D 모델, SDK, 템플릿, 툴 등 여러분의 콘텐츠 제작에 날개를 달아줄 다양한 에셋을 제공합니다.

assetstore.unity.com

 

Easy 2D, 3D, VR, & AR software for cross-platform development of games and mobile apps. - Unity Store

Have a 2D, 3D, VR, or AR project that needs cross-platform functionality? We can help. Take a look at the easy-to-use Unity Plus real-time dev platform!

store.unity.com

 

Create 2D & 3D Experiences With Unity's Game Engine | Unity Pro - Unity Store

Unity Pro software is a real-time 3D platform for teams who want to design cross-platform, 2D, 3D, VR, AR & mobile experiences with a full suite of advanced tools.

store.unity.com

[투네이션]

 

-

 

toon.at

[Patreon]

 

WER's GAME DEVELOP CHANNEL님이 Game making class videos 창작 중 | Patreon

WER's GAME DEVELOP CHANNEL의 후원자가 되어보세요. 아티스트와 크리에이터를 위한 세계 최대의 멤버십 플랫폼에서 멤버십 전용 콘텐츠와 체험을 즐길 수 있습니다.

www.patreon.com

[디스코드 채널]

 

Join the 베르의 게임 개발 채널 Discord Server!

Check out the 베르의 게임 개발 채널 community on Discord - hang out with 399 other members and enjoy free voice and text chat.

discord.com

 

반응형

static 

정적 변수와 정적 함수 그리고 정적 클래스

 

static 키워드는 변수나 함수, 클래스에 정적 속성을 부여하는 것으로 클래스로부터 객체를 생성하지 않고 변수나 함수를 호출할 수 있도록 해주는 것이다.

 

 

정적 변수

 

public class StaticTestClass

{

    public static int score;

}

 

정적 변수를 선언하기 위해서는 위의 예시 코드와 같이 static 키워드를 붙여서 변수를 정의하면 된다. 이렇게 선언한 정적 변수는 클래스로부터 객체를 생성하지 않아도 [클래스명.변수이름]의 형식으로 곧바로 사용할 수 있게 된다. 

 

public class MainClass

{

    public void Main()

    {

        StaticTestClass.score = 10;

    }

}

 

클래스의 일반 멤버 변수는 클래스의 객체가 생성될 때, 각 객체마다 따로 생기지만, 정적 변수는 해당 클래스가 처음으로 사용되는 때에 한 번만 초기화되어 계속 동일한 메모리를 사용하게 된다.

 

 

도식으로 보면 위의 그림과 같다. 정적 변수를 포함한 클래스 A의 객체를 두 개를 생성하여 각 이름을 object1, object2라고 했을 때, 각 인스턴스에는 정적 변수가 포함되지 않으며, 일반 멤버 변수만 포함된다. 클래스 A의 정적 변수는 클래스 A가 처음 사용되는 시점에 별도의 메모리 공간에 할당된다.

 

 

생성된 객체에 정적 변수가 포함되지 않는 것은 실제로 객체를 생성해서 멤버 변수를 찾았을 때, 목록에 나오지 않는 것을 보면 확인할 수 있다.

 

 

정적 함수

 

public class StaticTestClass

{

    public static int score;

 

    public int memberInt;

 

    public static void StaticFunction()

    {

        score = 10;  // static 변수는 호출할 수 있다.

        memberInt = 10;  // static 함수 내에서 멤버변수는 호출할 수 없다.

    }

}

 

public class MainClass
{
    public void Main()
    {
        StaticTestClass.score = 10;
        StaticTestClass.StaticFunction();
    }
}

 

함수를 선언할 때, static 키워드를 붙여서 함수를 정의하면 정적 함수를 만들 수 있다. 이 정적 함수 역시 [클래스명.함수이름]의 형식으로 객체를 생성하지 않고 곧바로 호출할 수 있다.

 

단, 정적 함수는 객체가 생성되기 전에 호출이 가능하기 때문에, 정적 함수 내에서는 정적 변수가 아닌 일반 멤버 변수를 호출할 수 없다.

 

 

정적 클래스

 

public static class StaticTestClass

{

    public static int score;

 

    static StaticTestClass()

    {

        score = 10;

    }

 

    public static void StaticFunction()

    {

        score = 20;

    }

}

 

정적 클래스는 모든 멤버가 정적 변수 혹은 정적 함수로 이루어진 것으로 객체를 생성할 수 없는 클래스이다. 모든 정적 멤버 변수 및 정적 멤버 함수는 [클래스명.변수이름] 혹은 [클래스명.함수이름]으로 호출된다.

 

정적 클래스는 정적 생성자를 가질 수 있는데 이 정적 생성자는 public, protected, private 등의 액세스 한정자를 사용할 수 없으며, 매개변수 역시 가질 수 없다.

 

[유니티 어필리에이트 프로그램]

아래의 링크를 통해 에셋을 구매하시거나 유니티를 구독하시면 수익의 일부가 베르에게 수수료로 지급되어 채널의 운영에 도움이 됩니다.

 

에셋스토어

여러분의 작업에 필요한 베스트 에셋을 찾아보세요. 유니티 에셋스토어가 2D, 3D 모델, SDK, 템플릿, 툴 등 여러분의 콘텐츠 제작에 날개를 달아줄 다양한 에셋을 제공합니다.

assetstore.unity.com

 

Easy 2D, 3D, VR, & AR software for cross-platform development of games and mobile apps. - Unity Store

Have a 2D, 3D, VR, or AR project that needs cross-platform functionality? We can help. Take a look at the easy-to-use Unity Plus real-time dev platform!

store.unity.com

 

Create 2D & 3D Experiences With Unity's Game Engine | Unity Pro - Unity Store

Unity Pro software is a real-time 3D platform for teams who want to design cross-platform, 2D, 3D, VR, AR & mobile experiences with a full suite of advanced tools.

store.unity.com

[투네이션]

 

-

 

toon.at

[Patreon]

 

WER's GAME DEVELOP CHANNEL님이 Game making class videos 창작 중 | Patreon

WER's GAME DEVELOP CHANNEL의 후원자가 되어보세요. 아티스트와 크리에이터를 위한 세계 최대의 멤버십 플랫폼에서 멤버십 전용 콘텐츠와 체험을 즐길 수 있습니다.

www.patreon.com

[디스코드 채널]

 

Join the 베르의 게임 개발 채널 Discord Server!

Check out the 베르의 게임 개발 채널 community on Discord - hang out with 399 other members and enjoy free voice and text chat.

discord.com

 

반응형

프로그래밍을 할 때 있어서 모든 일이 처음 설계한대로 흘러간다면 얼마나 좋을까? 하지만 Hello World를 출럭하는 프로그램이 아닌 이상에야 그런 일은 있을 수 없다.

 

확장성을 위해, 재사용성을 위해, 더 나은 구조를 위해 코드와 설계는 변하기 마련이다. 그 와중에 많은 함수나 변수, 클래스가 추가되고 삭제된다. 물론 혼자서만 하는 작업이라면 코드를 바꾸고 바꾼 코드를 바로 적용하면 되지만, 코드 베이스를 만드는 사람과 그 베이스를 이용해서 작업하는 사람이 따로 있는 상황이라면 이야기가 조금 달라진다.

 

만약 베이스를 작업하는 사람이 몇몇의 함수를 삭제하고 다른 이름의 함수로 대체했다면 그 베이스를 응용하는 사람 역시 그에 대한 사실을 알아야 한다. 물론 일반적인 상식으로 베이스 작업자가 베이스를 변경했다면 다른 작업자에게 바로 알려주고 다른 작업자는 바로 변경하는게 맞는 이야기지만, 사람과 사람 사이의 의사소통이라는게 말처럼 쉽기만 하던가. 베이스 작업자가 변경사항을 몇 개는 빠뜨리고 알려줄 수도 있고, 다른 작업자는 이야기를 들었지만 까먹을 수도 있는 일이다. 여튼 의사소통 과정에서 문제가 발생했다면 다른 작업자는 뜬금없이 바뀐 베이스 코드에 당황을 금치 못할 것이다.

 

그런 상황을 맞이한 다른 작업자는 당연히 문제를 해결하기 위해서 베이스 작업자에게 어떻게 변경된 것인지 물어보던지, 코드를 뒤져서 바뀐 함수를 적용하던지 하는 노력을 하겠지만 아무래도 이런 방식은 해결 속도도 느릴 뿐더러 효율적이지 못하다.

 

그렇기 때문에 나온 해결책이 바로 [Obsolete] 라는 어트리뷰트이다.

 

class TestClass
{
    [Obsolete]
    public void Function1()
    {
    }
}

 

더 이상 사용하지 않거나 그럴 예정인 클래스나 함수, 변수의 앞에 [Obsolete] 어트리뷰트를 붙여주면 된다. 그렇게 하면 해당 함수를 호출할 때 초록색 밑줄과 함께 더 이상 사용하지 않는 함수라는 경고가 뜬다.

 

 

그리고 툴팁에서는 함수 앞에 [deprecated]가 붙게 된다.

 

이 [Obsolete]는 세 가지 방식의 오버로딩을 지원한다.

 

class TestClass
{

    [Obsolete]
    public void Function1()
    {

    }

    [Obsolete("Not use anymore.")]
    public void Function2()
    {

    }

    [Obsolete("Not use anymore.", true)]
    public void Function3()
    {

    }
}

 

[Obsolete] :: 더 이상 사용하지 않는 코드라는 경고만 출력한다.

 

[Obsolete(string message)] :: 더 이상 사용하지 않는다는 경고에 추가적인 메시지를 남길 수 있다. 이 메시지를 통해 더 이상 사용하지 않는 코드 대신에 사용할 코드를 사용자에게 알릴 수 있다.

 

[Obsolete(string message, bool error)] :: 추가적인 로그와 함께 이 코드를 사용할 경우에 컴파일 에러를 띄울지를 결정한다. true를 넣어주면 컴파일 에러를 띄워서 이 코드를 사용하면 컴파일을 할 수 없게 된다.

 

 

이런 식으로 [Obsolete]를 적절하게 사용하면 베이스 작업자는 코드 작업만으로 다른 작업자에게 코드가 변경되었음을 알림과 동시에 그에 대한 해결책도 전해줄 수 있다. 베이스 작업자가 코드를 변경하고 다른 작업자에게 변경사항을 일일이 알리는 것보다 훨씬 빠르고 효율적인 해결책이다.

 

 

[유니티 어필리에이트 프로그램]

아래의 링크를 통해 에셋을 구매하시거나 유니티를 구독하시면 수익의 일부가 베르에게 수수료로 지급되어 채널의 운영에 도움이 됩니다.

 

에셋스토어

여러분의 작업에 필요한 베스트 에셋을 찾아보세요. 유니티 에셋스토어가 2D, 3D 모델, SDK, 템플릿, 툴 등 여러분의 콘텐츠 제작에 날개를 달아줄 다양한 에셋을 제공합니다.

assetstore.unity.com

 

Easy 2D, 3D, VR, & AR software for cross-platform development of games and mobile apps. - Unity Store

Have a 2D, 3D, VR, or AR project that needs cross-platform functionality? We can help. Take a look at the easy-to-use Unity Plus real-time dev platform!

store.unity.com

 

Create 2D & 3D Experiences With Unity's Game Engine | Unity Pro - Unity Store

Unity Pro software is a real-time 3D platform for teams who want to design cross-platform, 2D, 3D, VR, AR & mobile experiences with a full suite of advanced tools.

store.unity.com

[투네이션]

 

-

 

toon.at

[Patreon]

 

WER's GAME DEVELOP CHANNEL님이 Game making class videos 창작 중 | Patreon

WER's GAME DEVELOP CHANNEL의 후원자가 되어보세요. 아티스트와 크리에이터를 위한 세계 최대의 멤버십 플랫폼에서 멤버십 전용 콘텐츠와 체험을 즐길 수 있습니다.

www.patreon.com

[디스코드 채널]

 

Join the 베르의 게임 개발 채널 Discord Server!

Check out the 베르의 게임 개발 채널 community on Discord - hang out with 399 other members and enjoy free voice and text chat.

discord.com

 

반응형

나는 C++ 프로그래머라서 그런지 C#의 문법적인건 가끔 까먹는 경우가 많다.

 

C++의 경우에는 부모 클래스의 생성자를 자식 클래스의 생성자에서 호출할때는 이니셜라이저에 부모 클래스 이름으로 호출해주면 됐었다.

 

C++의 경우

class Parent;
{
private:
    int i;
public:
    Parent(int i) : i(i) {  }
}

class Child : public Parent
{
private:
    int j;
public:
    Child(int i, int j) : Parent(i), j(j) {  }    // 부모의 이름으로 부모의 생성자를 호출할 수 있다.
}

 

하지만 C#의 경우는 약간 달라서 부모 클래스의 이름으로는 부모 클래스의 생성자를 호출할 수 없고 base 키워드를 사용해야 한다.

 

C#의 경우

public class Parent;
{
    private int i;

    public Parent(int i)
    {
        this.i = i;
    }
}

public class Child : Parent
{
    private int j;

    public Child(int i, int j) : base(i)    // 부모 클래스의 생성자를 호출하려면 base 키워드를 사용해야 한다.
    { 
        this.j = j;
    }
}

 

C# 프로그래밍 책을 한 번 훑어보면서 봤던 내용인데 C#코딩을 자주하는 편은 아니라 정확한 방법을 까먹어서 다시 찾아보게 되었다.

 

 

 

[유니티 어필리에이트 프로그램]

아래의 링크를 통해 에셋을 구매하시거나 유니티를 구독하시면 수익의 일부가 베르에게 수수료로 지급되어 채널의 운영에 도움이 됩니다.

 

에셋스토어

여러분의 작업에 필요한 베스트 에셋을 찾아보세요. 유니티 에셋스토어가 2D, 3D 모델, SDK, 템플릿, 툴 등 여러분의 콘텐츠 제작에 날개를 달아줄 다양한 에셋을 제공합니다.

assetstore.unity.com

 

Easy 2D, 3D, VR, & AR software for cross-platform development of games and mobile apps. - Unity Store

Have a 2D, 3D, VR, or AR project that needs cross-platform functionality? We can help. Take a look at the easy-to-use Unity Plus real-time dev platform!

store.unity.com

 

Create 2D & 3D Experiences With Unity's Game Engine | Unity Pro - Unity Store

Unity Pro software is a real-time 3D platform for teams who want to design cross-platform, 2D, 3D, VR, AR & mobile experiences with a full suite of advanced tools.

store.unity.com

[투네이션]

 

-

 

toon.at

[Patreon]

 

WER's GAME DEVELOP CHANNEL님이 Game making class videos 창작 중 | Patreon

WER's GAME DEVELOP CHANNEL의 후원자가 되어보세요. 아티스트와 크리에이터를 위한 세계 최대의 멤버십 플랫폼에서 멤버십 전용 콘텐츠와 체험을 즐길 수 있습니다.

www.patreon.com

[디스코드 채널]

 

Join the 베르의 게임 개발 채널 Discord Server!

Check out the 베르의 게임 개발 채널 community on Discord - hang out with 399 other members and enjoy free voice and text chat.

discord.com

 

반응형

+ Recent posts