접근 제한자

상태
시작 전
담당자
날짜
숫자
0
여러분은 접근 제한자에 대해 제대로 이해하고 계신가요? 코딩을 하다보면 접근제한자라고 하는 public, private 라는 키워드를 자주 접하실 겁니다. 하지만 이를 왜 사용하는지, 정확히 어떤 개념인지 막연하게만 알고 계신 분들이 많을 텐데요. 이번에는 접근제한자에 대해 자세히 알아보도록 하겠습니다.

접근 제한자란?

접근 제한자는 클래스의 멤버(변수, 메서드, 속성 등)가 어디서 접근 가능한지를 결정하는 키워드입니다.
C#에서 주로 사용하는 접근제한자에는 public, private, protected, internal 등이 있는데요. 무슨 차이가 있는지 예시를 보며 알아보도록 하겠습니다.

1. public

public 접근 제한자는 해당 멤버가 어디서든 접근 가능해야 할 때 사용됩니다. 예를 들어, 게임 캐릭터의 이름이나 체력 등을 외부에서 자유롭게 조회하거나 설정할 수 있도록 할 때 사용됩니다.
public class GameCharacter { // 캐릭터의 이름과 건강 상태를 외부에서 접근할 수 있도록 public으로 선언 public string Name { get; set; } public int Health { get; set; } // 캐릭터의 상태를 출력하는 public 메서드 public void DisplayStatus() { Console.WriteLine($"{Name} has {Health} health points."); } } // 다른 클래스나 외부 코드에서 자유롭게 접근 가능 public class Game { public void CreateCharacter() { // GameCharacter 클래스의 public 멤버에 접근 GameCharacter character = new GameCharacter { Name = "Archer", Health = 100 }; character.DisplayStatus(); } }
C#
복사
그런데 만약 잘못된 값을 외부 코드에서 입력할 시 어떻게 될까요?
public class GameCharacter { public string Name { get; set; } public int Health { get; set; } public void DisplayStatus() { Console.WriteLine($"{Name} has {Health} health points."); } } public class Game { public void Play() { GameCharacter character = new GameCharacter { Name = "Archer", Health = 100 }; character.DisplayStatus(); // 외부 코드에서 Health를 임의로 수정할 수 있음 character.Health = -50; // 부정확한 값을 설정 character.DisplayStatus(); } }
C#
복사
예를 들어 이런 식으로 외부 코드에서 체력을 -50으로 설정하면 체력이 음수가 됩니다. 이는 버그를 유발하여 예상치 못한 동작을 하게 할 수 있습니다.
이런 상황을 방지하기 위해 private 접근 제한자를 사용합니다.

2. private

private으로 선언된 멤버는 해당 클래스 내부에서만 접근할 수 있고, 외부 클래스나 다른 코드에서는 접근할 수 없습니다. 이를 통해 클래스 내부의 상태를 보호하고, 잘못된 사용을 방지할 수 있습니다.
public class GameCharacter { public string Name { get; set; } private int health; // 체력을 private로 선언 public GameCharacter(string name, int initialHealth) { Name = name; health = initialHealth; } public void TakeDamage(int damage) { if (damage < 0) throw new ArgumentException("Damage cannot be negative."); health -= damage; if (health < 0) health = 0; // 체력은 음수가 될 수 없음 Console.WriteLine($"{Name} took {damage} damage and now has {health} health points."); } public void DisplayStatus() { Console.WriteLine($"{Name} has {health} health points."); } } public class Game { public void Play() { GameCharacter character = new GameCharacter("Archer", 100); character.DisplayStatus(); character.TakeDamage(30); // 외부 코드에서 health를 직접 수정할 수 없어 데미지를 주는 방식으로 체력 변경 character.DisplayStatus(); } }
C#
복사
이처럼 체력을 private 으로 선언하면 외부 코드에서 health 값을 임의로 수정할 수 없습니다. 따라서 TakeDamage 메서드를 통해서만 health를 변경할 수 있으며, 이 메서드는 체력이 0 이하로 떨어지는 것을 방지합니다.
이를 통해 클래스 내부의 상태를 안전하게 유지하고, 잘못된 값이 설정되는 것을 방지합니다.

3. protected

protected 접근 제한자는 해당 멤버가 클래스와 이를 상속받는 자식 클래스에서만 접근 가능하도록 할 때 사용됩니다. 예를 들어, 캐릭터의 기본 속성을 자식 클래스에서도 사용하도록 할 때 사용됩니다.
public class GameCharacter { // 자식 클래스에서 접근할 수 있도록 protected로 선언 protected int Health { get; set; } public GameCharacter(int initialHealth) { Health = initialHealth; } } public class Warrior : GameCharacter { public Warrior(int initialHealth) : base(initialHealth) { } // 공격 메서드 (protected 멤버에 접근) public void Attack() { Health -= 10; // 부모 클래스의 protected 멤버에 접근 } } public class Program { public static void Main() { Warrior warrior = new Warrior(100); warrior.Attack(); // Health 멤버는 protected로 외부에서 직접 접근할 수 없음 } }
C#
복사
위의 코드를 보면 Warrior 클래스는 GameCharacter 클래스를 상속받아 Health 멤버에 접근할 수 있습니다. Healthprotected로 설정되어 Warrior 클래스 내에서 접근할 수 있지만, Program 클래스에서는 직접 접근할 수 없습니다.
즉, 상속을 통해 부모 클래스의 일부 기능이나 데이터를 자식 클래스에서 재사용하거나 확장을 할 때, 클래스 내부의 상태를 직접 수정하지 못하도록 보호하면서 상속받은 자식 클래스에서는 이를 안전하게 사용할 수 있습니다.

4. internal

접근 제한자는 특정 어셈블리 내에서만 멤버에 접근할 수 있도록 제한합니다. 이를 통해 외부 어셈블리에서의 접근을 차단하고, 내부 구현을 보호하는 데 유용합니다.
// MyLibrary.dll 어셈블리 내부 // 내부 구현 세부 사항을 보호하기 위해 internal로 선언된 클래스 internal class InternalService { internal void PerformOperation() { Console.WriteLine("작동 중..."); } } // 외부에서 사용할 API 클래스 public class PublicService { private InternalService _internalService = new InternalService(); // 외부에서 호출할 수 있는 public 메서드 public void Execute() { _internalService.PerformOperation(); // internal 멤버에 접근 } }
C#
복사
// MainApp.exe 어셈블리 (다른 어셈블리) public class Program { public static void Main() { // PublicService를 통해 기능을 사용 PublicService service = new PublicService(); service.Execute(); // PublicService의 public 메서드를 호출 // InternalService 클래스와 PerformOperation 메서드에 직접 접근할 수 없음 } }
C#
복사
InternalService 클래스는 internal로 선언되어 MyLibrary.dll 어셈블리 내에서만 접근할 수 있습니다.
PublicService 클래스는 public으로 선언되어 외부 어셈블리에서 사용 가능하며, Execute 메서드는 InternalServicePerformOperation 메서드를 호출합니다.
외부 어셈블리인 MainApp.exe에서는 PublicServicepublic 메서드인 Execute를 통해 InternalService의 기능을 사용할 수 있습니다.

접근 제한자 사용 이유

접근 제한자를 올바르게 사용하면 코드의 보안성과 가독성을 높일 수 있습니다.
접근 제한자는 클래스의 멤버가 어디서 접근 가능한지를 결정하므로, 불필요한 접근을 막아 코드의 일관성을 유지하고 버그를 줄이는 데 도움이 됩니다. 또한, 외부에서 접근하지 말아야 할 내부 구현을 감출 수 있어, 모듈 간의 독립성을 높이고 유지 보수를 쉽게 만듭니다.

기본 접근 제한자

만약 여러분이 코드를 작성하는데 접근 제한자를 명시하지 않으면 어떻게 될까요? 그러한 경우, 기본 접근 제한자가 적용되는데요.
기본 접근 제한자란, 접근 제한자를 명시하지 않았을 때 컴파일러가 자동으로 적용하는 접근 제한자의 종류를 의미합니다.

1. 클래스의 기본 접근 제한자 : internal

접근 제한자를 명시하지 않으면, 클래스는 같은 어셈블리 내에서만 접근할 수 있습니다.
// DefaultClass는 internal로 간주됨 class DefaultClass { public void Display() { Console.WriteLine("This is a default class."); } }
C#
복사

2. 메서드, 속성, 필드, 생성자의 기본 접근 제한자 : private

접근 제한자를 명시하지 않으면, 메서드, 속성, 필드, 생성자는 기본적으로 private로 설정됩니다. 즉, 해당 클래스 내부에서만 접근할 수 있습니다.
public class MyClass { // 기본적으로 private으로 간주됨 int number; // private 필드 // 기본적으로 private으로 간주됨 void MyMethod() // private 메서드 { number = 10; } // 기본적으로 private으로 간주됨 MyClass() // private 생성자 { number = 0; } }
C#
복사

3. 인터페이스, 열거형 (enum), 구조체 (struct)의 기본 접근 제한자 : internal

접근 제한자를 명시하지 않으면, 인터페이스, 열거형, 구조체는 같은 어셈블리 내에서만 접근할 수 있습니다.
// DefaultInterface는 internal로 간주됨 interface DefaultInterface { void MyMethod(); } // DefaultEnum은 internal로 간주됨 enum DefaultEnum { Value1, Value2 } // DefaultStruct는 internal로 간주됨 struct DefaultStruct { public int Value; }
C#
복사
기본 접근 제한자를 알아두면 코드의 자동 적용 규칙을 정확히 이해하면, 명시적으로 접근 제한자를 설정할 때의 의도를 명확히 할 수 있습니다.

결론

지금까지 우리는 주로 사용하는 접근 제한자에 대해 알아보았습니다.
접근 제한자는 코드의 보안성을 강화하고, 모듈화 및 캡슐화를 통해 유지 보수성을 높이며, 의도된 설계를 명확히 하는 데 중요한 역할을 합니다. 접근 제한자에 대한 이해는 예상치 못한 접근 문제를 방지하고, 코드의 일관성과 안정성을 유지하는 데 필수적입니다. 여러분들이 접근 제한자를 이해하고 올바르게 설정함으로써 코드의 품질을 향상시키고, 후에 팀원들과의 효율적인 협업과 디버깅 하는 데에 도움이 되었으면 좋겠습니다.