[20251226] Extension Method & ETC

SmartBear·2025년 12월 26일

확장 메서드 (extended method)

확장 메서드는 기존 구현된 클래스에 기능을 추가하지 않고 해당 클래스에 기능을 추가할 수 있는 기능이다.

문법

public static class CLASS_NAME
{
    public static RETURN_TYPE METHOD_NAME(this TARGET_CLASS_NAME VARIABLE, ...) 
    {
        ... Your Code ...
    }
}

코드 예시

public class ExtendedMethodStudy
{
    public void Run()
    {
        int a = 4;
        Console.WriteLine(a.IsEven());
        Console.WriteLine(a.Sum(6, 8, 10));
        Console.WriteLine(a.IsOdd());
        Console.WriteLine(a.Multiplier(4, 5, 6));
    }
}

public static partial class ExtensionMethods
{
    public static bool IsEven(this int number)
    {
        return number % 2 == 0;
    }

    public static int Sum(this int number, params int[] values)
    {
        foreach (int v in values)
        {
            number += v;
        }
        return number;
    }
}

public static partial class ExtensionMethods
{
    public static bool IsOdd(this int number)
    {
        return number % 2 == 1;
    }

    public static int Multiplier(this int number, params int[] values)
    {
        foreach (int v in values)
        {
            number *= v;
        }
        return number;
    }
}

사용처?

많이 사용하게 될지 아닐지는 케이스 by 케이스.
잘 사용되면 유용한 Utility 를 사내에 제공할 수 있게 되겠지만,
그렇지 않으면 사장되는 불필요한 코드를 넣는꼴이 될 수 있다.

그 밖에 C#

불변 객체(Imutable)

기존 참조 타입은 변수를 복사하게 되면 같은 주소를 가리키기 때문에 일부 데이터 변경시 원본 값이 변경된다. (얕은 복사)
하지만 불변속성이 있는 객체는 복사하여 변조시 원본 데이터가 변경되지 않고 변조한 객체는 깊은 복사가 되어 변조한 객체만 데이터가 변경된다.
말이 조금 어렵지만 코드를 보면 쉽게 이해 된다.

코드 예제

먼저 string을 통해 확인해보자.

string a = "hello world";
string b = a;
b = "hellworld";
Console.WriteLine(a); // hello world
Consolw.WriteLine(b); // hellworld

string은 대표적인 불변 객체이다. string참조 타입이지만 string b = a; 가 실행될 때 참조된 주소값이 복사되는, 앝은 복사가 아니라
깊은 복사를 통해 복사본을 만들었기 때문에 새로운 string b가 생성된다고 보면 된다.

string Type 사용시 주의 사항

string의 경우, 위에 이야기 했듯 문자열을 많이 사용할 수 록 heap메모리를 많이 사용하게 된다.
때문에 문자열을 많이 다루어야 하는 프로그램인 경우 불필요한 heap메모리가 많이 사용되거나 GC가 많은 일을 해야할 경우가 발생할 수 있다.

이에, C# 에서는 StringBuilder라는 기능을 제공하고 있다.
MSDN - StringBuilder

StringBuilder sb = new StringBuilder();
sb.Append("Hello World");
Console.WriteLine(sb);  // Hello World
Console.WriteLine(sb[5]);  // W
sb.Replace("Hello", "Bye");
Console.WriteLine(sb);  // Bye World
StringBuilder sb2 = sb;
sb2.Replace("Bye", "Hell");
Console.WriteLine(sb);  // Hell World
Console.WriteLine(sb2);  // Hell World

Nullable

참조 타입의 자료형에는 null을 넣을 수 있다. 하지만 값 타입에는 null을 넣을 수 없다.
하지만, 별도의 문법을 통해 null을 넣을 수 있다.

int a; // 0
int? a = null; // null

삼황연산자

타 언어에서도 많이 사용하는 연산자로, 조건식에 대한 결과를 간단히 적을 때 주로 사용 된다.

int a = 1;
// 문법; 조건식 ? true 일때 : false 일때
Console.WriteLine(a == 1 ? "a 는 1이다." : "a는 1이 아니다");  // a는 1이다.

조건이나 반환해야 하는 내용이 복잡하거나 길면 오히려 가독성이 떨어지니 주의하자.

?, ?? 연산자

  • ? 연산자는 위에 언급했듯 값타입nullable하게 할 때도 사용하지만, .을 이용한 호출시 null일 경우 수행하지 않게 하는 (NullException 회피) 경우도 사용한다.
  • ??삼황연산자와 비슷하게 사용 가능하다. ?? 를 기준으로 null일 경우 좌측을, null이 아닐 경우 우측을 실행한다.
someInstance?.run();  // someInstance 가 null 이면 아무 것도 실행되지 않고, instance 면 run 함수 실행
//  대상 참조     ?? null 이면 실행
a = someInstance ?? false;  // someInstance 가 null 일 경우 false

const & readonly

constreadonly 는 변하지 않아야 하는 값에 대한 것은 동일하지만 그 성질은 다르다.

특징constreadonly
값 결정 시점컴파일 타임 (Compile-time)런타임 (Runtime)
초기화선언 시점에만 가능선언시 또는 생성자 내에서 가능
Static 여부암시적 Static선택 가능 (Static/Instance)
타입 제한기본 타입만 가능모든 타입 가능 (Custom Type 포함)
용도절대 불변 값 (PI, ...)객체내에서 변동이 없어야 할 경우(사용자 ID, ...)

컴파일 타임(Compile Time) vs 런 터임(Runtime)

  • 컴파일 타임소스코드기계어로 변환되는 시점을 이야기 한다. 즉, 이 시점에는 메모리에 데이터를 할당하거나 하지 않는다.
  • 런타임은 프로그램이 실제로 실행되는 시점을 이야기 한다. 즉, 이 시점에는 진짜로 데이터를 메모리에 할당하게 된다고 보면된다.

여기 블로그에 아주 잘 정리되어 있다. ClydeHan 님 블로그
MSDN에는 정보가 파편화 되어있어 이해가 쉽지는 않았다 ㅠ

public class Tester
{
    public const int MyConst = 1;
    public static readonly int MyReadOnly = 1;
    public void Run()
    {
        Console.WriteLine(MyConst);
        Console.WriteLine(MyReadOnly);
    }
}
// ================================================
// IL Code
// [9 9 - 9 36]
IL_0001: ldc.i4.1
IL_0002: call         void [mscorlib]System.Console::WriteLine(int32)
IL_0007: nop

// [10 9 - 10 39]
IL_0008: ldsfld       int32 Tester::MyReadOnly
IL_000d: call         void [mscorlib]System.Console::WriteLine(int32)
IL_0012: nop

Tuple

Tuple 은 간단한 사용법으로는 한줄로 정의된 구조체와 비슷하다 볼 수 있다.
또한 Tuple을 이용한 리턴값을 여러개 반환이 가능하다.

// 간단한 초기화
(int x, int y, int z) Position = (1, 2, 3);  // 선언
Console.WriteLine(Position.x) // 1
Console.WriteLine(Position.y) // 2
Console.WriteLine(Position.z) // 3

// 여러 반환값 받기
public (bool, int) SomeMethod()
{
    return (true, 10);
}

(result, someValue) = SomeMethod();  // 여러값 반환

근데 자주 사용되는 데이터 구조라면 되도록 구조체로 사용하는 것이 좋다.
잠시 일시적으로 사용시에만 활용하자.

Optional Parametor

아래 코드를 보며 확인하자.

public class MyClass 
{
    public int Health;
    public Monster(int health = 50)  // default 값 제시 가능. 
    {
        Health = health;
    }
}

위와 같이 편한 기능이지만, 초기화 하려면 본래의 방법으로 하는게 좋다.
유지보수시 코드를 해석하는데 발목을 잡힐 수 있기 때문이다. 남용 금지.

profile
Python Dev with Infra -> Game Programmer

0개의 댓글