글 작성자: Doublsb

본 글은 공부하며 작성하였습니다. 정보를 얻으실 때 사실과 다르거나 부정확한 정보가 들어있을 수도 있습니다.

 

내용 출처

https://docs.microsoft.com/ko-kr/dotnet/csharp/tour-of-csharp/

C# 둘러보기 - C# 가이드

C#을 처음 사용하시나요? 언어의 기본 사항에 대해 알아봅니다. 이 개요에서 시작합니다.

docs.microsoft.com

 
최근에 기초를 더 탄탄하게 다져야 한다고 느껴서, C# 라이브러리를 읽고 정리해보기로 했다. 이전 글과 마찬가지로, 전체 내용보다는 새롭게 배웠거나 필요성을 느낀 내용들을 정리해보려 한다.


부호 있는 정수와 부호 없는 정수

부호 있는 정수 : sbyte, short, int, long
부호 없는 정수 : byte, ushort, uint, ulong
 
실구현에서는 오버플로우나 연산 관련 오류가 발생할 일이 없어 int만 사용했으나, 코딩 테스트를 겪으면서 깨알같은 중요성을 느꼈다. 특히 해커랭크.
막상 필요하다고 여기고 나니까 어딘가에 쓸 일이 있을 것 같기도 하고 그렇다.


튜플

(double, int) t1 = (4.5, 3);
print(t1.Item1);
(double Sum, int Count) t2 = (4.5, 3);
print($"Sum of {t2.Count} elements is {t2.Sum}");

 
튜플 또한 클래스나 구조체를 사용하지, 굳이 쓸 이유가 없다고 생각했었는데, 지역 변수로 사용한다면 클린 코드에 도움이 될 것 같았다. 무울론 잘 안 쓸 것 같다.


박싱/언박싱

int i = 123;
object o = i; //Boxing
int j = (int)o; //Unboxing

값 형식이 object 참조에 할당되면 박싱이 일어난다. o는 i를 담고 있지만, 참조 형태로 담게 된다.
라벨도 붙여져있지 않은 상자에 '과자'들을 넣은 게 박싱이라고 생각하면 된다.
언박싱은 이 상자에 '과자'들이 들어 있었는데...? 하면서 꺼내려고 시도하는 것이다. ...비유가 좀 그렇긴 한데.
 

아무튼, int는 값 형식이고, object는 참조 형식이다. 결론적으로 박싱과 언박싱은 값 <=> 참조를 의미하는 것이다.
비용이 비싸기 때문에, 이러한 현상이 발생하지 않게끔 조심해야 한다.
 
예전 NDC 자료에서 Enum 타입을 키로 사용하면 박싱/언박싱이 발생하기 때문에 주의해야 한다, 라는 말이 있었는데. 닷넷 4.0이 업데이트 되면서 옛말이 되었다. 굳이 레거시인 말을 쓰는 이유는 혹시나 닷넷 2.0을 쓸 수도 있어서...?
 
결론은 ArrayList 같은 복합 자료형은 웬만하면 쓰지 말자.


인터페이스 형식으로 암시적 변환하기

클래스 또는 구조체가 특정한 인터페이스를 구현하고 있으면, 해당 인터페이스 형식으로 암시적 변환이 가능하다.

EditBox editbox = new EditBox();
IControl control = editbox;
IDataBound dataBound = editbox;

이는 생각해보면 매우 익숙한데, LinQ를 사용할 때 List 타입을 IEnumerable 타입으로 변환하여 연산하는 것을 떠올려보면 된다.


Enum의 Flag 연산

[Flags]
public enum Days
{
    None      = 0,
    Monday    = 1,
    Tuesday   = 2,
    Wednesday = 4,
    Thursday  = 8,
    Friday    = 16,
    Saturday  = 32,
    Sunday    = 64,
    Weekend   = Saturday | Sunday
}
Days meetingDays = Days.Monday | Days.Wednesday | Days.Friday;
Console.WriteLine(meetingDays);
// Output:
// Monday, Wednesday, Friday

Days workingFromHomeDays = Days.Thursday | Days.Friday;
Console.WriteLine($"Join a meeting by phone on {meetingDays & workingFromHomeDays}");
// Output:
// Join a meeting by phone on Friday

Flag와 비트 연산을 사용하면 선택을 조합할 수 있다. 이 때, Flags Attribute를 선언해야 하고, 연결된 값은 제곱이어야 한다.
이진수로 변환해보면 알기 쉬운데, Weekend는 0100000과 1000000을 OR연산하여 1100000으로 만든 것이다.
그러므로 아래쪽 코드는 0010101 | 0011000 = 001000이므로, Friday인 것이다.
 
...switch로 enum의 공통 카테고리를 분류했던 과거의 나를 공격하자.
아래쪽 코드의 meetingDays를 출력했을 때 Monday, Wednesday, Friday가 나오는 건 좀 신기하군.


Nullable 유형

int? optionalInt = default;
int Int = default;

//Null
//0

자료형에서 null을 허용하게 만들고 싶으면 물음표를 붙이면 된다. 우와아아악!!!
코딩 테스트에서 잘 써먹었다.


접근 제한자

- public
- private
- protected
- internal : 액세스가 현재 어셈블리로 제한된다. dll을 떠올려보면 왜 사용하는지 이해하기 쉽다.
- protected internal : 두 제한자에 OR을 건 것. protected이거나 internal 상황에서만 참조 가능하다.
- private protected : internal이고 protected여야만 참조 가능하다. 이름 왜 이렇게 지었죠?


속성도 가상(virtual)일 수 있다

public class temp1
{
    protected int _test;
    public virtual int Test
    {
        get => _test;
        set => _test = value;
    }
}

public class temp2 : temp1
{
    public override int Test
    {
        get => 1;
        set => base.Test = value;
    }
}

 
 
이렇게 만들고, print(new temp2().Test)를 하면 1이 나온다. 어떻게 보면 당연한 것인데 당연하게 생각하지 않았음.


인덱서

class SampleCollection<T>
{
   private T[] arr = new T[100];

   public T this[int i]
   {
      get { return arr[i]; }
      set { arr[i] = value; }
   }
}

예시는 제네릭이지만, 어떤 자료형이든 상관없다.
해당 클래스를 인덱스 형태로 접근 가능하게 만들어준다. 커스텀 클래스를 배열이나 리스트 형태로 만들 수 있는 것.
Length나 Count 속성이 없기에, 필요하면 직접 만들어줘야 한다. 커스텀 클래스니까.


StringBuilder 좀 써라

String은 변경할 수 없는 형식이다. 그러니까 만들 때마다 인스턴스가 생성된다고!
"안녕" + "하세요" + "?" 는 3개의 쓰레기 인스턴스를 만드니까, 부하가 발생한다.
 
StringBuilder는 Append를 할 때 인스턴스를 생성시키지 않는다. 그러니까 쓰라고!
나중에 바꿔야지 하지 말고 바로 쓰라고! 나에게 격렬하게 외친다...

반응형