---
title: "이름은 같고 투입구만 다르다"
description: "Console.WriteLine 에 숫자를 넣어도 문자열을 넣어도 되는 이유입니다. 같은 이름의 메서드가 여러 벌 있습니다."
author: "유니얼"
pubDate: 2026-09-08
category: "programming/csharp/basics"
tags: ["C#", "기초"]
canonical: https://blog.unialgames.com/posts/csharp-overloading/
---
지금까지 아무 생각 없이 써 온 것이 있습니다.

```csharp
Console.WriteLine(42);
Console.WriteLine("안녕");
Console.WriteLine(3.14);
Console.WriteLine(true);
```

넣는 값의 타입이 전부 다른데 이름은 하나입니다.
메서드는 매개변수 타입을 정해서 만든다고 했는데, 어떻게 다 받을까요.

답은 간단합니다. **`WriteLine` 이 한 개가 아닙니다.**
숫자를 받는 것, 문자열을 받는 것, 실수를 받는 것이 따로 있고 이름만 같습니다.

> **하는 일이 같으면 이름도 같아야 읽힙니다. 받는 것만 다르게 여러 벌 만듭니다.**

이걸 오버로딩이라고 합니다.

## 이름이 하나여야 읽힌다

오버로딩이 없으면 이렇게 됐을 겁니다.

```csharp
Console.WriteLineInt(42);
Console.WriteLineString("안녕");
Console.WriteLineDouble(3.14);
```

쓰는 쪽이 매번 "지금 넣는 게 무슨 타입이더라" 를 생각해야 합니다.
타입을 바꾸면 메서드 이름도 같이 고쳐야 합니다.

**하는 일이 같은데 이름이 다르면 부담은 쓰는 쪽이 집니다.**
오버로딩은 그 부담을 만드는 쪽으로 옮깁니다.

```csharp
void Print(int value)
{
    Console.WriteLine("숫자: " + value);
}

void Print(string value)
{
    Console.WriteLine("글자: " + value);
}

Print(42);       // 숫자: 42
Print("안녕");    // 글자: 안녕
```

컴파일러가 넣은 값의 타입을 보고 어느 쪽을 부를지 고릅니다.
**부를 때 정해지는 것이 아니라 컴파일할 때 정해집니다.**

## 무엇을 보고 고르나

컴파일러가 보는 것은 **매개변수의 타입, 개수, 순서** 셋뿐입니다.

```csharp
void Print(int a)              // 타입이 다르다
void Print(string a)

void Print(int a)              // 개수가 다르다
void Print(int a, int b)

void Print(int a, string b)    // 순서가 다르다
void Print(string a, int b)
```

전부 됩니다. 셋 중 하나라도 다르면 다른 메서드로 봅니다.

**반환 타입은 보지 않습니다.**

```csharp
int GetValue()
string GetValue()      // 컴파일 에러
```

왜 안 되는지는 이렇게 생각하면 됩니다.

```csharp
GetValue();
```

이 줄만 보고 어느 쪽을 불러야 할지 정할 수가 없습니다.
돌려받은 값을 안 쓰는 코드도 되니까요.
**고르는 근거는 넘기는 것에만 있어야 합니다.** 매개변수가 완전히 같으면 이름을 다르게 지어야 합니다.

매개변수 이름도 안 봅니다.

```csharp
void Print(int score)
void Print(int point)      // 컴파일 에러
```

앞에서 매개변수 이름은 메서드 안에서만 통한다고 했습니다.
밖에서는 안 보이는 이름이니 고르는 근거가 될 수 없습니다.

## 기본값을 정해 두면 생략할 수 있다

거의 같은데 매개변수 하나만 있고 없고인 경우가 있습니다.

```csharp
void Greet(string name)
{
    Greet(name, "안녕하세요");
}

void Greet(string name, string message)
{
    Console.WriteLine(name + "님, " + message);
}
```

두 벌을 만들 것 없이 **기본값**을 적어 두면 됩니다.

```csharp
void Greet(string name, string message = "안녕하세요")
{
    Console.WriteLine(name + "님, " + message);
}

Greet("서병필");                  // 서병필님, 안녕하세요
Greet("서병필", "오랜만입니다");   // 서병필님, 오랜만입니다
```

규칙이 하나 있습니다. **기본값이 있는 매개변수는 목록 맨 뒤에 와야 합니다.**

```csharp
void Greet(string message = "안녕", string name)    // 컴파일 에러
```

앞에 있으면 `Greet("서병필")` 이 어느 자리에 넣은 것인지 알 수 없습니다.
넣은 값은 **앞에서부터 차례로** 채워지기 때문입니다.

## 이름을 붙이면 순서를 안 지켜도 된다

기본값이 여러 개일 때 문제가 생깁니다.

```csharp
void Setup(int width = 800, int height = 600, bool fullscreen = false)
```

`fullscreen` 만 바꾸고 싶은데, 앞에서부터 채워지니 앞의 두 개를 다 적어야 합니다.

```csharp
Setup(800, 600, true);      // 안 바꿀 값을 굳이 적었습니다
```

이럴 때 **이름을 붙여서** 넘깁니다.

```csharp
Setup(fullscreen: true);
```

컴파일러가 이름을 보고 어느 자리인지 압니다. 순서를 지킬 필요도 없습니다.

```csharp
Setup(height: 1080, width: 1920);
```

이름을 붙이면 읽기도 좋아집니다.

```csharp
CreateWindow(1920, 1080, true, false);
CreateWindow(width: 1920, height: 1080, fullscreen: true, resizable: false);
```

아래쪽은 주석 없이도 읽힙니다.
**`true` 나 `false` 를 여러 개 넘길 때는 이름을 붙이는 편이 낫습니다.**
숫자만 봐서는 무엇을 켜고 끄는지 알 수 없습니다.

## 어디까지 묶을 것인가

오버로딩은 **하는 일이 같을 때** 씁니다. 이름이 같으니 쓰는 사람은 같은 일을 기대합니다.

```csharp
double Average(int a, int b)
double Average(List<int> nums)
```

이건 좋습니다. 둘 다 평균을 구하고, 재료만 다릅니다.

```csharp
void Save(string path)        // 파일에 저장
void Save(int userId)         // 서버에 전송
```

이건 이름을 나눠야 합니다. 하는 일이 다릅니다.
같은 이름이 붙어 있으면 읽는 사람이 같은 일이라고 믿습니다.
**오버로딩은 문법이 허락하는 범위가 아니라 읽는 사람의 기대에 맞춰 씁니다.**

## 정리

- 이름이 같고 매개변수가 다른 메서드를 여러 벌 만드는 것이 오버로딩입니다.
- 컴파일러가 넘긴 값의 타입, 개수, 순서를 보고 고릅니다. 컴파일할 때 정해집니다.
- 반환 타입과 매개변수 이름은 고르는 근거가 아닙니다. 그것만 다르면 컴파일 에러입니다.
- 매개변수 하나만 있고 없고라면 오버로딩 대신 기본값을 씁니다.
- 기본값이 있는 매개변수는 목록 맨 뒤에 와야 합니다.
- 이름을 붙여 넘기면 순서를 안 지켜도 되고, 읽기도 좋아집니다.
- 하는 일이 다르면 이름을 나눕니다. 같은 이름은 같은 일이라는 약속입니다.