C#

[C#] 연산자

sunlight-dby 2025. 4. 7. 18:43

 

 

'이것이 C#이다 개정판'의 chapter 4를 정리한 글입니다.

 


삼항 연산자

   조건식 ? 참일_때의_값 : 거짓일_때의_값

 

삼항 연산자의 사용에 대한 장단점을 if문과 비교하여, 삼항 연산자의 사용에 대해 의문을 가질 수 있습니다.

사실 우리에게 익숙한 것은 if문이 훨씬 더 익숙하기 때문이죠.

 

하지만 삼항 연산자를 사용했을 때 장점이 명확한 부분들이 있기 때문에, 삼항 연산자도 잘 기억해둬야 합니다.

 

[장점]

  • 간결합니다.
    • 코드가 짧고 간결해져서 한 줄로 표현이 가능합니다.
    • 간단한 조건부 로직을 빠르게 작성할 수 있습니다.
  • 값이 직접적으로 결정되는 상황에서 명확하게 표현할 수 있습니다.
    • 때에 따라 다르겠지만, 간단한 경우에는 가독성을 높일 수도 있습니다.
      조건과 결과가 명확하게 드러나기 때문이죠.
  • 임시 변수(객체)를 생성하지 않습니다.
    • 임시 객체를 생성하지 않기 때문에, 메모리 사용을 줄이고 가비지 컬렉션의 부담을 감소시킬 수 있습니다.
int score = (player.IsAlive) ? 100 : 0;

 

[단점]

  • 로직 또는 조건이 복잡해지면, 가독성 저하와 제어 흐름의 복잡성으로 이어집니다.
    • 복잡한 조건이 포함될 경우 가독성이 떨어질 수 있습니다.
    • 복잡한 조건과 로직이 필요하여 삼항 연산자가 중첩되면 구문에 대한 이해가 떨어질 수 있습니다.
      • 로직이 복잡지면 오히려 if문을 사용하는 것이 더 명확할 수 있습니다.
string result = (condition1) ? "A" : (condition2) ? "B" : "C";

 

[정리]

이렇듯, 간단한 조건이 필요할 때는 삼항 연산자를 사용하여 간결하게 표현이 가능합니다.

하지만 복잡한 로직과 조건은 if문을 사용하는 것이 더 명확할 것입니다.

 


 

null 조건부 연산자

   객체_이름?.객체의_멤버

 

?. 연산자는 객체의 멤버에 접근하기 전에 해당 객체가 null인지 검사하여 그 결과가 참(즉, 객체가 null)이면 그 결과로 null을 반환하고, 그렇지 않은 경우에는 접근하려는 멤버를 반환합니다.

 

?[ ] 연산자 또한 비슷한 역할을 하지만, 객체의 멤버 접근이 아닌 배열과 같은 컬렉션 객체의 첨자를 이용한 참조에 사용됩니다.

 

※ 컬렉션(Collections) 객체는 컬렉션 네임스페이스에서 제공하는 컬렉션을 말합니다.
    나중 글에서 더 자세히 설명하겠지만, 간단하게 대표적인 컬렉션들만 정리해 보겠습니다.

System.Collections 설명
ArrayList    크기가 가변적인 배열로, 다양한 데이터 타입을 저장할 수 있습니다.
Hashtable    Key - Value 쌍으로 데이터를 저장하는 해시 테이블입니다.
Queue    선입선출(FIFO) 방식으로 데이터를 저장하는 큐입니다.
Stack    후입선출(LIFO) 방식으로 데이터를 저장하는 스택입니다.
Dictionary Base    해시 테이블을 기반으로 한 클래스로, 사용자 정의 딕셔너리를 만들 때 사용합니다.

 

[예시]

using System.Collections;
using static System.Console;

namespace StringFormatDatetime
{
    class MainApp
    {
        static void Main(string[] args)
        {
            using System.Collections;
            using static System.Console;

namespace NullConditionalOperator
    {
        class MainApp
        {
            static void Main(string[] args)
            {
                ArrayList a = null;

                a?.Add("야구");  // a?.가 null을 반환하므로 Add() 메소드는 호출되지 않습니다.
                a?.Add("축구");

                WriteLine($"Count : {a?.Count}");
                WriteLine($"{ a?[0]}");
                WriteLine($"{ a?[1]}");
    


            a = new ArrayList();  // a는 이제 더 이상 null이 아닙니다.

                a?.Add("야구");
                a?.Add("축구");

                WriteLine($"Count : {a?.Count}");
                WriteLine($"{a?[0]}");
                WriteLine($"{a?[1]}");
            }
        }
    }
}
    }
}


// 실행결과
Count :			// a?.가 null을 반환하므로 "Count :" 외에는 아무것도 출력하지 않습니다.


Count : 2
야구
축구

 

 


 

비트 연산자

연산자 이름 설명 지원 형식
<<    왼쪽 시프트 연산자   첫 번째 피 연산자의 비트를 두 번째
  피연산자의 수만큼 왼쪽으로 이동시킵니다.

  (비트를 옮긴 후, 남아있는 부분에 대해서는
   양수면 0, 음수면 1을 채웁니다.)
  첫 번째 피연산자는 int, uint,
  long, ulong이며 두 번째
  피 연산자는 int 형식만
  지원합니다.
>>    오른쪽 시프트 연산자   첫 번째 피 연산자의 비트를 두 번째
  피연산자의 수만큼 오른쪽으로 이동시킵니다.

  (비트를 옮긴 후, 남아있는 부분에 대해서는
   양수면 0, 음수면 1을 채웁니다.)
  <<와 같습니다.
&    논리곱(AND) 연산자   두 피연산자의 비트 논리곱을 수행합니다.   정수 계열 형식과 bool 형식에
  대해 사용할 수 있습니다.
|     논리합(OR) 연산자   두 피연산자의 비트 논리합을 수행합니다.   &와 같습니다.
^    배타적 논리합(XOR) 연산자   두 피연산자의 비트 배타적 논리합을
  수행합니다.
  &와 같습니다.
~    보수(NOT) 연산자   피 연산자의 비트를 0은 1로, 1은 0으로 
  반전시킵니다. 단항 연산자입니다.
  int, uing, long, ulong에 대해
  사용이 가능합니다.

 

 

[시프트 연산자 예시]

using System;
using static System.Console;

namespace ShiftOperator
{
	class MainApp
    {
    	static void Main(string[] args)
        {
            WriteLine("Testing << ...");
            
            int a = 1;
            WriteLine("a      : {0:D5} (0x{0:X8})", a);
            WriteLine("a << 1 : {0:D5} (0x{0:X8})", a << 1);
            WriteLine("a << 2 : {0:D5} (0x{0:X8})", a << 2);
            WriteLine("a << 5 : {0:D5} (0x{0:X8})", a << 5);
            
            
            WriteLine("\nTesting >> ...");
            
            int b  = 255;
            WriteLine("b      : {0:D5} (0x{0:X8})", b);
            WriteLine("b >> 1 : {0:D5} (0x{0:X8})", b >> 1);
            WriteLine("b >> 2 : {0:D5} (0x{0:X8})", b >> 2);
            WriteLine("b >> 5 : {0:D5} (0x{0:X8})", b >> 5);
            
            
            WriteLine("\nTesting >> 2...");
            
            int c = -255;
            WriteLine("c      : {0:D5} (0x{0:X8})", c);
            WriteLine("c >> 1 : {0:D5} (0x{0:X8})", c >> 1);
            WriteLine("c >> 2 : {0:D5} (0x{0:X8})", c >> 2);
            WriteLine("c >> 5 : {0:D5} (0x{0:X8})", c >> 5);
        }
    }
}
// 실행 결과
Testing << ...
a      : 00001 (0x00000001)
a << 1 : 00002 (0x00000002)
a << 2 : 00004 (0x00000004)
a << 5 : 00032 (0x00000020)

Testing >> ...
b      : 00255 (0x000000FF)
b >> 1 : 00127 (0x0000007F)
b >> 2 : 00063 (0x0000003F)
b >> 5 : 00007 (0x00000007)

Testing >> 2...
c      : -00255 (0xFFFFFF01)
c >> 1 : -00128 (0xFFFFFF80)
c >> 2 : -00064 (0xFFFFFFC0)
c >> 5 : -00008 (0xFFFFFFF8)

 


 

null 병합 연산자

null 병합 연산자는 왼쪽 피연산자가 null인지를 평가한 후, null이라면 오른쪽 피 연산자를 반환하고, 아니라면 왼쪽 피연산자의 값을 반환합니다.

 

[사용 방법]

int? a = null;
Console.WriteLine($"{a ?? 0}"); // a는 null이므로 0이 출력됩니다.

a = 99;
Console.WriteLine($"{a ?? 0}");  // a는 null이 아니므로 99가 출력됩니다.

string str = null;
ConsoleWriteLine($"{str ?? "Default"}");  // str은 null이므로 "Default"가 출력됩니다.

str = "Specific";
ConsoleWriteLine($"{str ?? "Default"}");  // str은 null이 아니므로 "Specific"이 출력됩니다.

 

[주의할 점]

개념과 사용 방법은 간단하지만 주의할 점이 있습니다.

 

null 병합 연산자가 지원하는 형식은 Nullable<T> 형식 또는 참조 형식만을 지원합니다.

값 형식에서는 null 병합 연산자가 지원되지 않으므로 주의하길 바랍니다.

 

[예시]

int a = 100;
Console.WriteLine($"{a ?? 0}");

// 위의 경우에 CS0019라는 컴파일러 오류가 발생합니다.
// "'??' 연산자는 'int' 및 'int' 형식의 피연산자에 적용할 수 없습니다." 라는 문구를 동반합니다.

// 수정된 구문
int? a = 100;
Console.WriteLine($"{a ?? 0}");

// 이렇게 수정하게 되면 null 병합 연산자를 사용하는 의미가 없지만
// 컴파일러 오류를 해결하기 위해서는 해당 방식처럼 a를 Nullable 타입으로 선언 및 초기화하여야 합니다.

 


 

연산자의 우선 순위

우선순위 종류 연산자
1   증가 / 감소 연산자 및
  null 조건부 연산자
   후위 ++/-- 연산자   ?.   ?[ ]
2   증가/감소 연산자    전위 ++/-- 연산자
3   산술 연산자   *   /   %
4   산술 연산자   +  -
5   시프트 연산자   <<   >>
6   관계 연산자   <   >   <=   >=   is   as
7   관계 연산자   ==   !=
8   비트 논리 연산자   &
9   비트 논리 연산자   ^
10   비트 논리 연산자   |
11   논리 연산자   &&
12   논리 연산자   ||
13   null 병합 연산자   ??
14   조건(삼항) 연산자   ?:
15   할당 연산자   =   *=   /=   %=   +=   -=   <<=   >>=   &=   ^=   |=