열거형 두번째 이야기로 비트플래그에 대해서 이야기하겠습니다. 비트플래그를 이해하기 위해서는 비트에 대한 개념이 있어야 합니다.


비트플래그에서는 비트를 구성하는 0과 1을 참 거짓으로 표현하여 현재 상태를 나타내는 것입니다.

우선 0은 거짓을 표현하고 1은 참을 표현해요.

예를 들어 과일을 표현하는 enum이 있다고 하겠습니다.

public enum Fruit
{
    None = 0,
    Apple = 1,
    Banana = 2,
    Peach = 4
}

비트플래그를 위해서 항상 None이라는 것이 필요하고 0으로 설정합니다. 그리고 다음 enum부터 1, 2, 4, 8, 16이런식으로 표현합니다.

여기서 0, 1, 2, 4, 8, 16이란 숫자에 주목해야하는데요.

이 숫자를 이진수로 표현해보겠습니다.

(10)                (2)
0          00000000000
1          00000000001
2          00000000010
4          00000000100
8          00000001000
16        00000010000

이제 이 숫자들이 어떤 특징이 있는지 보이시나요?
바로 이진수의 자리마다 한개의 1을 사용하고 있습니다.
잘 이해가 안가시죠? 이제 enum과 위에 숫자들을 연관시켜보겠습니다.

Peach    Banana    Apple
   0               0              0           
   0               0              1           
   0               1              0           
   1               0              0           

이진수 000 의 경우 십진수로 0이고 어떤 과일도 선택안된 상태인 None 입니다.

이진수 001 의 경우 십진수로 1이고 사과가 선택된 상태입니다.

이진수 010 의 경우 십진수로 2이고 바나나가 선택된 상태입니다.

이진수 100 의 경우 십진수로 4이고 복숭아가 선택된 상태입니다.

각 자리수에 0이면 선택되지 않은거고 1이면 선택된 상태가 됩니다.

따라서 110은 복숭아와 바나나가 선택된 상태가 됩니다.

코드로 보면

Fruit.Banana | Fruit.Peach 라서 쓰면
010 | 100 이라는 비트연산이 되고
연산결과는 110이됩니다. 해석하면 바나나 또는 복숭아라는 뜻이 되기에 선택한 enum에 복숭아와 바나나가 모두 선택된 뜻처럼 사용되는거죠.
참고로 enum 에서 All 을 표현하기 위해서는 
~0 이라는 키워드를 사용하면 됩니다. 


public enum Fruit
{
    None = 0,
    Apple = 1,
    Banana = 2,
    Peach = 4,
    All = ~0,
}



C#을 공부하다보면 조건문을 만나게 됩니다.
이때 논리연산을 많이 사용하는데요. 우선 기본 개념부터 이야기하면

1. && 논리연산
AND 연산은 모든 조건이 true 인 경우 해당 연산이 true가 되는 연산입니다.

ex)
true && true = true
true && true && false = true
false && false = false

2. || 논리연산
OR 연산은 한 조건이라도 true이면 true를 반환하는 조건입니다.

ex)
true || false = true
false || false = false
true || true = true

이게 기본 개념인데요. 이런 논리연산을 조건문에 대입하는 경우 각 조건문의 위치가 중요합니다.

예를 들어 학생들의 점수가 기록된 DB에서 원하는 정보를 조건문으로 가져온다고 생각해볼께요.

학생중 성이 김씨이고 서울에 거주하면서 점수가 70점 이상인 학생들 조건문으로 찾는다고 가정할때

조건문의 순서를 김씨를 먼저 찾고 그리고(&&) 서울에 거주하고 그리고(&&) 점수가 70점이상인 경우라고 하면 코드를 읽을때 쉽게 이해할 수 있어요. 그리고 이 경우 각 조건을 확인하고 하나의 조건이라도 만족하지 않을 경우 다음 조건은 검사하지 않아요.

그래서 검사하는데 필요한 비용이 작은 순서로 검사하는 것이 좋아요.

OR 논리연산의 경우 한가지 조건이라도 만족할 경우 다음 조건을 검사하지 않기 때문에 이 경우도 필요한 비용이 작은 순서로 검사하는 것이 좋겠죠?


4가지 비트연산에 대해서 간단하게 알아보겠습니다. 우선 비트란 0과 1로 이루어진 단위입니다. 그럼 비트 연산이라고 하면 0과 1로 연산을 한다는 것이죠.
비트 연산의 종류로는 AND, OR, XOR, NOT 이 있는데요. 가장 많이 사용하는 4가지에 대해서 하나씩 알아보겠습니다.

1. AND (&)
AND 연산은 0이 하나라도 있으면 0이 반환됩니다.
ex)
1 & 1 = 1
1 & 1 & 1 = 1
1 & 0 = 0
0 & 1 = 0
0 & 0 = 0


2. OR (|)
OR 연산은 AND 연산과 반대되는 연산으로 1이 하나라도 있으면 1을 반환합니다.
ex)
0 | 0 = 0
0 | 1 = 1
1 | 0 | 0 = 1
1 | 1 | 1 = 1


3. XOR (^)
XOR 연산은 연산을 하는 두개의 비트가 서로 다른 경우에 1을 반환합니다.
ex) 
1 ^ 1 = 0
0 ^ 0 = 0
1 ^ 0 = 1
0 ^ 1 = 1


4. NOT (~)
NOT 연산은 1을 0으로, 0을 1로 변환합니다. 
ex) 
~1 = 0
~0 = 1 


대부분의 프로그래밍 언어에서는 enum이라는 것을 지원합니다.
enum은 프로그래머가 원하는 상수를 만들 수 있는데요. 프로그래밍에서 enum을 사용하는 것은 매우 중요합니다. 잘 사용하면 정말 효율적이죠.
우선 enum을 만드는 방법부터 알아보겠습니다.

public enum Grade
{
    A,
    B,
    C,
    D,
    F
}

이런식으로 접근제한자 다음에 enum이라는 키워드를 적고 해당 enum의 이름을 적어주면 됩니다. 그리고 안에 해당 enum들의 원소를 적어줍니다.

enum을 사용하는 프로그래머가 볼때는 글자이지만, 내부적으로 숫자로 인식됩니다. 선언된 순서대로 0, 1, 2, 3, 4라는 숫자가 지정됩니다. 이건 기본값이고 원하면 숫자를 지정하는 것도 가능합니다.

public enum Grade
{
    A = 5,
    B = 4,
    C = 3,
    D = 2,
    F = 0
}

이렇게 다른 숫자를 지정해서 사용할 수 있습니다. 저는 개인적으로 이런식으로 숫자 지정하는 것은 피해라라고 하고 싶어요.
각 열거형에 특정한 값을 지정하고 싶다면 attribute를 이용하는 것이 효과적입니다. 열거형의 숫자는 내부적으로 컴퓨터가 사용하는 것이기 때문에 기본값을 사용하는 것이 좋아요.

하지만 기본값을 사용하지 않는 경우가 있는데요. 비트플래그를 사용하는 경우입니다.
비트플래그에 대해서는 다른 글에서 다루겠습니다.

마지막으로 enum을 사용하는 방법을 알아보겠습니다.

public class Student
{
   public Grade mathGrade = Grade.A;
   .....
}

이런식으로 사용할 enum인 Grade를 적고 . 을 이용해서 원소를 적어줍니다. 열거형의 경우 등호나 부등호를 이용하서 비교하는 것이 가능하고 조건문이나 switch문에서도 활용할 수 있습니다. 열거형을 많이 사용하면 코드가 읽기 쉽고 깔끔해지는 장점이 있습니다.

개인적으로 enum을 많이 쓰는 것을 권장하고 있어요.


var이 생소한 분들도 있고 익숙한 분들도 있겠죠.
많은 분들이 var과 object에 대해서 큰 고민없이 사용하고 있는데요.

익명타입인 var은 C# 3.0에서부터 지원하는 기능입니다. 일반적으로 변수를 선언할때 명시적으로 변수의 타입을 선언하는데요.

익명타입을 사용할 경우 자동으로 할당받은 타입으로 인식됩니다. 이는 object와는 큰 차이가 있습니다. object는 해당 타입을 boxing하는 과정을 통해서 기존의 타입을 감추는 것이였지만, var에서는 이러한 과정이 없습니다.

프로그래머는 타입을 신경쓰지 않고 var를 사용하면 컴파일러가 자동으로 변수의 타입을 인식하는 것이죠.

일반적으로 var이 사용되는 경우는 2가지가 있는데요. 가장 흔하게 사용되는 경우는 이미 정해진 타입의 변수를 새로운 메모리에 할당하는 경우입니다.

예를 들면


var numbers = new List<int>();

이런 코드이죠. 이미 오른쪽에서 리스트를 생성하여 numbers라는 변수에 할당하였죠. 이 경우 numbers는 별도의 unboxing 과정이 없어도 리스트로 인식됩니다.

이런 경우로 사용할 경우 지켜줄 원칙이 있는데요. 다른 사람이 자신의 코드를 읽을때 new로 생성한 변수는 해당 변수의 타입을 쉽게 알 수 있지만, 함수나 다른 변수로부터 가져오는 경우 한번 더 확인하는 과정이 필요하기 때문에 왠만하면 var를 사용하지 않거나 변수이름에 타입을 유추할 수 있도록 적어주는 것이 중요합니다. (물론 개인적인 의견입니다.)

2번째 경우는 new 라는 키워드를 이용해서 익명타입을 생성하는 경우인데요.


var students = new[]
{
     new { Name = "KSY", Score = "89" },
     new { Name = "LTW", Score = "50" },
     new { Name = "KHJ", Score = "37" },
}

이런식으로 생성하게 되면 별도의 클래스를 생성하지 않아도 자신이 원하는 타입의 변수를 만들 수 있습니다. 하지만 익명타입의 경우 다른 사람이 쉽게 파악하기 어렵다는 단점이 있기 때문에 내부적으로 사용하는 것을 추천합니다.
System는 다양한 기능을 제공하고 있습니다.
그중에서 DateTime에 대해서 이야기하겠습니다.

DateTime은 시간과 날짜에 대한 정보를 담고 있습니다.

컴퓨터 바탕화면을 기준으로 좌측 하단에 나오는 시간이 바로 DateTime입니다.

DateTime에는 Now라는 변수가 있는데요.
이는 Now를 호출하는 시점의 시간을 반환합니다.
 그리고 ToString(" ")이라는 함수를 이용해서 원하는 결과를 가져올 수 있습니다.

아래 코드는 순서대로 년도, 월, 일, 시간, 분, 초를 가져오는 방법입니다.


string year = System.DateTime.Now.ToString("yyyy");
string month = System.DateTime.Now.ToString("MM");
string day = System.DateTime.Now.ToString("dd");
string hour = System.DateTime.Now.ToString("hh");
string minute = System.DateTime.Now.ToString("mm");
string second = System.DateTime.Now.ToString("ss");


그리고 C#에서는 DateTime을 통해서 복잡한 기능을 쉽게 사용할 수 있는데요.

바로 부등호나 등호를 이용해서 날짜를 비교할 수 있다는 것이죠.


DateTime past = new DateTime();
DateTime now = new DateTime();
DateTime future = new DateTime();


이렇게 3가지 과거, 현재, 미래를 표현하는 DateTime이 있다고 할때, past < now는 true기 됩니다.

따라서 달력을 이용해서 어떤 프로그램을 만들때 부등호나 등호를 사용하면 쉽게 날짜에 대한 검색이 가능하겠죠.

+ Recent posts