C# 접근 한정자 이해하기
이 글에서는 C#에서 타입, 메서드, 변수의 가시성과 접근성을 정의하는 접근 제한자에 대해 자세히 살펴보겠습니다. Tim Corey는 자신의 비디오 " C# 접근 제한자(public 및 private 외) - 무엇이며, 어떻게 사용하고, 모범 사례는 무엇인가 "에서 다양한 접근 제한자를 설명하고 콘솔 애플리케이션에서 실제 사용법을 보여줍니다.
이 글에서는 Tim이 다룬 내용을 설명하고, 이해를 돕기 위한 코드 예제도 함께 제공합니다. 제공된 타임스탬프를 통해 영상을 따라가면서 더욱 실감나는 경험을 할 수 있습니다.
접근 제한자란 무엇인가요?
소개
팀 코리는 접근 제한자를 소개하며, 접근 제한자가 C#에서 누가 리소스를 보고 사용할 수 있는지 를 결정한다고 설명합니다. 일반적으로 사용되는 공용 및 개인 접근 제한자는 익숙하지만, Tim은 서로 다른 6가지 접근 제한자 와 그 사용 사례를 살펴봅니다.
데모 애플리케이션 설명
팀은 다양한 접근 제어자가 어떻게 작동하는지 보여주기 위해 간단한 애플리케이션을 설치합니다. 이 애플리케이션은 콘솔 사용자 인터페이스와 데모 라이브러리로 구성되어 있으며, 둘 다 .NET Framework 로 작성되었습니다.
프로젝트 구조:
- 콘솔 UI : 접근 제한자를 테스트하기 위한 콘솔 애플리케이션입니다.
- 데모 라이브러리 : 다양한 접근 제어자를 보여주는 클래스 라이브러리입니다.
public class AccessDemo
{
private void PrivateDemo() { }
internal void InternalDemo() { }
public void PublicDemo() { }
}public class AccessDemo
{
private void PrivateDemo() { }
internal void InternalDemo() { }
public void PublicDemo() { }
}1. 개인
이것은 무엇인가:
private 한정자는 해당 메서드, 필드 또는 속성에 대한 접근을 해당 클래스가 정의된 내부로만 제한합니다.
코드 예시:
public class AccessDemo
{
private void PrivateDemo()
{
Console.WriteLine("Private method can only be accessed within this class.");
}
public void CallPrivateDemo()
{
PrivateDemo(); // Works because it's within the same class
}
}public class AccessDemo
{
private void PrivateDemo()
{
Console.WriteLine("Private method can only be accessed within this class.");
}
public void CallPrivateDemo()
{
PrivateDemo(); // Works because it's within the same class
}
}설명: PrivateDemo 메서드는 AccessDemo 클래스 내에서만 접근 가능합니다. 영상에서 Tim은 다른 클래스가 같은 프로젝트에 있더라도 클래스 외부에서는 해당 클래스에 접근할 수 없다는 것을 보여줍니다.
모범 사례 : 클래스의 내부 작동 방식에 대한 접근을 제한하여 애플리케이션의 다른 부분에서 직접 수정할 수 없도록 하려면 private 키워드를 사용하십시오.
2. 내부
이것은 무엇인가:
내부 접근 제한자를 사용하면 동일한 어셈블리(프로젝트) 내에서만 해당 메서드 또는 속성에 접근할 수 있습니다. 이는 private 접근 제한자보다 범위가 더 넓으며, 동일한 프로젝트 내의 모든 클래스를 포함합니다.
코드 예시:
public class AccessDemo
{
internal void InternalDemo()
{
Console.WriteLine("Internal method is accessible within the same assembly.");
}
}public class AccessDemo
{
internal void InternalDemo()
{
Console.WriteLine("Internal method is accessible within the same assembly.");
}
}설명: InternalDemo 메서드는 같은 어셈블리 내의 모든 클래스에서 접근할 수 있지만, 다른 어셈블리에서는 접근할 수 없습니다. 영상에서 팀은 내부 접근 권한은 동일 프로젝트 내부에서는 허용하지만 외부에서는 접근을 차단한다는 것을 보여줍니다.
모범 사례 : 현재 어셈블리 내에서만 사용하도록 의도된 메서드 또는 속성(예: 외부 프로젝트에 노출되어서는 안 되는 헬퍼 함수 또는 유틸리티)에는 internal을 사용하십시오.
3. 공공
이것은 무엇인가:
public 한정자를 사용하면 다른 클래스나 어셈블리에서 해당 메서드 또는 속성에 접근할 수 있습니다. 이는 가장 관대한 접근 권한 수준입니다.
코드 예시:
public class AccessDemo
{
public void PublicDemo()
{
Console.WriteLine("Public method can be accessed from any class.");
}
}public class AccessDemo
{
public void PublicDemo()
{
Console.WriteLine("Public method can be accessed from any class.");
}
}설명: PublicDemo 메서드는 어디서든지 접근할 수 있으며, 같은 어셈블리의 다른 클래스나 다른 어셈블리에서도 접근할 수 있습니다. Tim은 특히 라이브러리에서 메서드를 노출할 때 public이 가장 일반적인 접근 제한자임을 보여줍니다.
모범 사례 : API 엔드포인트 또는 널리 사용되는 유틸리티와 같이 애플리케이션의 다른 부분이나 외부 프로젝트에서 접근해야 하는 메서드 및 속성에는 public 키워드를 사용하세요.
4. 보호됨
이것은 무엇인가:
protected 접근 제어자는 해당 제어자가 정의된 클래스 내에서는 물론, 파생 클래스(상속)에서도 해당 메서드 또는 속성에 접근할 수 있도록 합니다. 이 한정자는 객체 지향 프로그래밍, 특히 상속의 경우에 유용합니다.
코드 예시:
public class AccessDemo
{
protected void ProtectedDemo()
{
Console.WriteLine("Protected method can be accessed within the class and derived classes.");
}
}
public class DerivedClass : AccessDemo
{
public void CallProtectedDemo()
{
ProtectedDemo(); // Accessible because of inheritance
}
}public class AccessDemo
{
protected void ProtectedDemo()
{
Console.WriteLine("Protected method can be accessed within the class and derived classes.");
}
}
public class DerivedClass : AccessDemo
{
public void CallProtectedDemo()
{
ProtectedDemo(); // Accessible because of inheritance
}
}설명: ProtectedDemo 메서드는 AccessDemo 클래스와 이 클래스를 상속하는 모든 클래스에서 접근할 수 있습니다. Tim은 protected가 흔하지는 않지만 상속을 다룰 때 매우 유용하다고 설명합니다.
모범 사례 : 파생 클래스가 특정 메서드나 속성에 접근할 수 있도록 허용하되, 클래스 계층 구조 외부에서는 접근할 수 없도록 하려면 protected 키워드를 사용하십시오.
5. 개인 보호
이것은 무엇인가:
개인 보호 수정자는 개인 및 보호 규칙을 결합합니다. 이는 동일한 어셈블리 내의 정의 클래스 및 파생 클래스 내의 메서드 또는 속성에 대한 액세스를 제한합니다. 이는 protected에 비해 상속 기반 접근 제어에 대해 더 높은 수준의 보호와 더욱 엄격한 경계를 제공한다는 의미입니다.
코드 예시:
public class AccessDemo
{
private protected void PrivateProtectedDemo()
{
Console.WriteLine("Private Protected method can be accessed within the same assembly and derived classes.");
}
}
public class DerivedClass : AccessDemo
{
public void CallPrivateProtectedDemo()
{
PrivateProtectedDemo(); // Accessible because of inheritance within the same assembly
}
}
public class UnrelatedClass
{
public void TestAccess()
{
// PrivateProtectedDemo(); // Error: Not accessible in unrelated classes
}
}public class AccessDemo
{
private protected void PrivateProtectedDemo()
{
Console.WriteLine("Private Protected method can be accessed within the same assembly and derived classes.");
}
}
public class DerivedClass : AccessDemo
{
public void CallPrivateProtectedDemo()
{
PrivateProtectedDemo(); // Accessible because of inheritance within the same assembly
}
}
public class UnrelatedClass
{
public void TestAccess()
{
// PrivateProtectedDemo(); // Error: Not accessible in unrelated classes
}
}설명: PrivateProtectedDemo 메서드는 AccessDemo을(를) 상속받고 같은 어셈블리에 존재하기 때문에 DerivedClass에서 접근할 수 있습니다. 그러나 이 클래스는 AccessDemo에서 상속받지 않았으므로 UnrelatedClass에서는 접근할 수 없습니다.
모범 사례 : 동일한 어셈블리 내에서 상속 접근을 엄격하게 제어해야 할 경우에만 private protected 접근 제한자를 신중하게 사용하십시오. 이는 어셈블리 간에 메서드나 속성을 노출하면 캡슐화가 손상될 수 있는 시나리오에서 특히 유용합니다.
6. 내부 보호
이것은 무엇인가:
보호된 내부 접근 수정자는 보호된 접근 수정자 수준과 내부 접근 수정자 수준을 결합합니다. 이를 통해 동일한 어셈블리 또는 파생 클래스에서 해당 클래스가 다른 어셈블리에 있더라도 접근할 수 있습니다.
코드 예시:
public class AccessDemo
{
protected internal void ProtectedInternalDemo()
{
Console.WriteLine("Protected Internal method can be accessed within the same assembly or from derived classes.");
}
}
public class DerivedClass : AccessDemo
{
public void CallProtectedInternalDemo()
{
ProtectedInternalDemo(); // Accessible due to inheritance
}
}public class AccessDemo
{
protected internal void ProtectedInternalDemo()
{
Console.WriteLine("Protected Internal method can be accessed within the same assembly or from derived classes.");
}
}
public class DerivedClass : AccessDemo
{
public void CallProtectedInternalDemo()
{
ProtectedInternalDemo(); // Accessible due to inheritance
}
}설명: ProtectedInternalDemo 메서드는 같은 어셈블리 내에서, 또한 어셈블리에 관계없이 모든 파생 클래스에서 접근할 수 있습니다.
모범 사례 : 파생 클래스(다른 어셈블리에 있는 클래스)와 동일 어셈블리 내의 클래스 모두에게 메서드를 노출하되 모든 사람에게 노출하지 않으려는 경우 protected internal을 사용하십시오.
모든 것을 공개하지 않는 이유는 무엇인가요?
팀 코리는 접근 제한자를 사용하는 것의 중요성과 모든 것을 공개해서는 안 되는 이유에 대해 설명합니다. 모든 것을 공개하는 것이 편리해 보일 수 있지만, 데이터 유출, 버그, 개발 과정의 혼란 등 상당한 위험을 수반합니다. 접근 제한자는 정보를 보호하고, 의도치 않은 공개 접근을 방지하며, 코드베이스의 명확성을 제공하기 위해 존재합니다.
1. 개인 정보 보호
팀은 사회보장번호(SSN)나 신용카드 번호와 같은 민감한 정보를 공개해서는 안 되는 이유에 대해 설명합니다. 그는 공개 접근으로 인해 데이터 노출이 발생하는 "나쁜 클래스"의 예를 제시합니다.
잘못된 예:
public class User
{
public string SSN; // Anyone can access and modify it directly
}public class User
{
public string SSN; // Anyone can access and modify it directly
}좋은 예:
public class User
{
private string ssn;
public string GetMaskedSSN()
{
return "XXX-XX-" + ssn.Substring(ssn.Length - 4);
}
public void SetSSN(string value)
{
// Add validation if needed
ssn = value;
}
}public class User
{
private string ssn;
public string GetMaskedSSN()
{
return "XXX-XX-" + ssn.Substring(ssn.Length - 4);
}
public void SetSSN(string value)
{
// Add validation if needed
ssn = value;
}
}2. 비공개 메서드 보안 강화
시작 시간: 35:11 팀은 비공개 메서드가 직접 접근해서는 안 되는 동작을 캡슐화하는 데 도움이 된다고 설명합니다. 그는 직원 오프보딩 같은 더 큰 프로세스의 일부로 DeleteUser 메서드를 예시로 사용합니다.
잘못된 예:
public class UserManager
{
public void DeleteUser(int userId)
{
// Deletes the user without considering related processes
}
}public class UserManager
{
public void DeleteUser(int userId)
{
// Deletes the user without considering related processes
}
}좋은 예:
public class UserManager
{
public void OffboardUser(int userId)
{
RevokeAccess(userId);
DeleteUser(userId); // Used privately as part of offboarding
}
private void DeleteUser(int userId)
{
// Internal logic to delete the user
}
private void RevokeAccess(int userId)
{
// Logic to revoke system access
}
}public class UserManager
{
public void OffboardUser(int userId)
{
RevokeAccess(userId);
DeleteUser(userId); // Used privately as part of offboarding
}
private void DeleteUser(int userId)
{
// Internal logic to delete the user
}
private void RevokeAccess(int userId)
{
// Logic to revoke system access
}
}3. 버그 방지
접근 제한자는 데이터가 적절한 유효성 검사를 거쳐 설정되거나 검색되도록 보장함으로써 버그를 방지합니다. 팀은 Age 속성을 포함하는 예를 들어 이를 설명합니다.
잘못된 예:
public class Person
{
public int Age; // Can be directly set to an invalid value
}public class Person
{
public int Age; // Can be directly set to an invalid value
}좋은 예:
public class Person
{
private int age;
public int Age
{
get { return age; }
set
{
if (value < 0 || value > 120)
throw new ArgumentOutOfRangeException("Age must be between 0 and 120.");
age = value;
}
}
}public class Person
{
private int age;
public int Age
{
get { return age; }
set
{
if (value < 0 || value > 120)
throw new ArgumentOutOfRangeException("Age must be between 0 and 120.");
age = value;
}
}
}4. 혼란 감소 및 명확성 향상
접근 제한자를 올바르게 사용하면 필요한 부분만 노출하여 개발을 간소화하고 혼란을 방지할 수 있습니다. 예를 들어, 수천 개의 메서드를 가진 애플리케이션에서 공개 메서드만 노출하면 개발자는 관련 옵션만 볼 수 있습니다.
예:
public class MathLibrary
{
public int Add(int a, int b) => a + b;
public int Subtract(int a, int b) => a - b;
private void LogCalculation(string operation, int result)
{
// Logging is internal and not exposed
}
}public class MathLibrary
{
public int Add(int a, int b) => a + b;
public int Subtract(int a, int b) => a - b;
private void LogCalculation(string operation, int result)
{
// Logging is internal and not exposed
}
}5. 대규모 애플리케이션 또는 라이브러리에서의 이점
Tim은 대규모 프로젝트의 경우 접근 제한자를 적절히 사용하면 라이브러리에서 필요한 부분만 노출되어 라이브러리를 사용하는 개발자의 인지 부하를 줄일 수 있다고 설명합니다.
예:
public class MathLibrary
{
public int Add(int a, int b) => a + b;
public int Subtract(int a, int b) => a - b;
private void LogCalculation(string operation, int result)
{
// Logging is internal and not exposed
}
}public class MathLibrary
{
public int Add(int a, int b) => a + b;
public int Subtract(int a, int b) => a - b;
private void LogCalculation(string operation, int result)
{
// Logging is internal and not exposed
}
}이러한 접근 제한자를 올바르게 사용하면 자신과 다음 사람의 업무를 더 쉽게 만들 수 있습니다.
결론
팀 코리는 C# 접근 제한자를 마스터하는 방법에 대한 명확하고 실용적인 가이드를 제공하며, 이를 효과적으로 사용하여 안전하고 유지 관리하기 쉬우며 전문적인 애플리케이션을 만드는 방법을 보여줍니다. 그의 상세한 설명과 실제 사례 덕분에 모든 수준의 개발자들이 이 주제를 쉽게 이해할 수 있습니다.
더 자세한 내용을 이해하고 이러한 개념이 실제로 어떻게 적용되는지 보려면 Tim의 전체 영상을 시청하고 그의 채널 에서 C# 및 기타 프로그래밍 주제에 대한 유용한 콘텐츠를 살펴보세요. 개발 실력 향상에 진지한 사람이라면 반드시 방문해야 할 자료입니다!

