C#/.NET(9): 접근 제어자는 무엇일까?
접근제어자를 알고는 있지만
접근 제어자는 JAVA를 공부했을 때, 알고 있었던 내용이다.
그 동안 안드로이드 스튜디오로 간단한 프로젝트를 만들어보기 위해 다루었기 때문에 대부분의 접근 제어자를 Public으로 사용하며 달리 신경쓰지 않았던 것 같다.
하지만, 접근 제어자의 사용은 만들어지는 시스템을 구성하는 멤버들의 구조 또는 정보 은닉(data hiding)을 위해 요청이 들어왔을 때, 필수적으로 지켜야 하는 원칙이라고 생각한다.
접근 제어자의 기능과 종류
접근 제어자를 통해 네임스페이스, 클래스 레벨로 접근 권한을 가질 수 있다.
C# 접근 제어자의 종류는 아래와 같다.
- Public : 모든 어셈블리에서 멤버에 접근할 수 있다.
- Internal : 같은 어셈블리 안에서만 멤버에 접근할 수 있다. 네임스페이스 레벨에서 접근 지정자를 따로 정의하지 않으면 기본적으로 internal로 정해진다.
- Protected : 같은 클래스 안에 있거나 해당 클래스를 상속받은 클래스의 멤버에 접근할 수 있다.
- Protected internal : 같은 어셈블리 안에서는 internal 처럼 작동한다. 어셈블리에서 벗어나면 Protected 처럼 작동한다.
- Private protected : 같은 어셈블리 안에서는 protected 처럼 작동한다. 어셈블리에서 벗어나면 멤버에 접근할 수 없으며, 상속된 클래스에서도 접근할 수 없다.
- Private : 같은 클래스 or struct 안에 있어야만 멤버에 접근할 수 있다. 클래스 레벨에서 접근 지정자를 따로 정의하지 않으면 기본적으로 Private으로 정해진다.
빌드 시, 어셈블리 → .dll

어셈블리란 무엇일까?
어셈블리는 컴파일을 통해서 나온 결과 파일을 C#에서는 어셈블리라고 한다. 빌드 시 만들어진 모든 파일들(.exe, .dll 등)을 모두 어셈블리라고 할 수 있다.
[Public 예시 코드]
AccessModifiers1.cs
using System;
namespace AccessModifiers1
{
class TestClass // namespace 레벨의 기본 접근 제어자는 internal
{
public string PublicField = "public";
}
class Program
{
public int num1 = 100;
static void Main(string[] args)
{
var testClassObject = new TestClass();
Console.WriteLine($"{testClassObject.PublicField}");
}
}
}
[Internal 예시 코드 (1)]
다른 어셈블리에서 해당 클래스의 멤버에 접근하려면 어떻게 해야할까?
-
순서1. 타겟 멤버와 클래스가 Public 으로 지정되어야 한다.
-
순서2. 접근하려는 어셈블리에서 타겟 멤버가 속한 네임스페이스를 using 으로 포함시켜야 한다.
이를 테스트해보기 위해 먼저, AccessModifiersAnotherAssembly라는 네임스페이스를 생성해주겠다. 아래와 같이 새로운 네임스페이스에서 AccessModifiers1 네임스페이스에 있는 TestClass에 접근하려고 하면, syntax 에러가 발생한다.
using System;
namespace AccessModifierAnotherAssembly
{
internal class Program
{
static void Main(string[] args)
{
// TestClass() 는 다른 어셈블리에 있음
var testClassObject = new TestClass(); // syntax 에러 발생
Console.WriteLine(testClassObject);
}
}
}
이유를 살펴보면, 접근해야되는 클래스(TestClass)의 접근 제어자는 현재 internal이다. 이 클래스의 접근 제어자를 public 으로 변경하여 다른 어셈블리에서 해당 클래스로 접근할 수 있게 해주어야 한다.
using System;
namespace AccessModifiers1
{
public class TestClass // public 으로 접근 제어자 변경
{
public string PublicField = "public";
}
class Program
{
public int num1 = 100;
static void Main(string[] args)
{
var testClassObject = new TestClass();
Console.WriteLine($"{testClassObject.PublicField}");
}
}
}
using AccessModifiers1; // 네임스페이스를 포함
using System;
namespace AccessModifierAnotherAssembly
{
internal class Program
{
static void Main(string[] args)
{
var testClassObject = new TestClass();
Console.WriteLine(testClassObject.PublicField); // 접근 가능
}
}
}
[Internal 예시 코드(2)]
using System;
namespace AccessModifiers1
{
public class TestClass
{
public string PublicField = "public";
internal string InternalField = "internal"; // internal 추가
}
class Program
{
public int num1 = 100;
static void Main(string[] args)
{
var testClassObject = new TestClass();
Console.WriteLine($"{testClassObject.PublicField}");
Console.WriteLine($"{testClassObject.InternalField}"); // 정상실행
}
}
}
using AccessModifiers1;
using System;
namespace AccessModifierAnotherAssembly
{
internal class Program
{
static void Main(string[] args)
{
var testClassObject = new TestClass();
Console.WriteLine(testClassObject.PublicField);
Console.WriteLine(testClassObject.InternalField); // syntax 에러
}
}
}
[Protected 예시 코드]
Protected는 어떠한 어셈블리에 있든 상관없이, 상속한 클래스에서는 접근이 가능하다.
using System;
namespace AccessModifiers1
{
public class TestClass
{
public string PublicField = "public";
internal string InternalField = "internal";
protected string ProtectedField = "protected";
}
public class ChildOfTestClass : TestClass // 상속
{
public ChildOfTestClass()
{
Console.WriteLine(base.ProtectedField); // Protected 멤버 접근
}
}
class Program
{
public int num1 = 100;
static void Main(string[] args)
{
var testClassObject = new TestClass();
Console.WriteLine($"{testClassObject.PublicField}");
Console.WriteLine($"{testClassObject.InternalField}");
// Console.WriteLine($"{testClassObject.ProtectedField}"); // 오류
}
}
}
using AccessModifiers1;
using System;
namespace AccessModifierAnotherAssembly
{
internal class Program
{
static void Main(string[] args)
{
var testClassObject = new TestClass();
Console.WriteLine(testClassObject.PublicField);
// Console.WriteLine(testClassObject.InternalField);
}
}
public class ChildOfTheClassFromAnotherAssembly : TestClass // 다른 어셈블리에서 상속
{
public ChildOfTheClassFromAnotherAssembly()
{
Console.WriteLine(base.ProtectedField); // 다른 어셈블리어도 상속된 클래스면 접근 가능
}
}
}
[Protected internal 예시 코드]
같은 어셈블리 안에 있으면, internal 처럼 작동하고 그렇지 않으면 Protected 처럼 작동한다.
using System;
namespace AccessModifiers1
{
public class TestClass
{
public string PublicField = "public";
internal string InternalField = "internal";
protected string ProtectedField = "protected";
protected internal string ProtectedInternalField = "protected internal"; // protected internal
}
public class ChildOfTestClass : TestClass
{
public ChildOfTestClass()
{
Console.WriteLine(base.ProtectedField);
}
}
class Program
{
public int num1 = 100;
static void Main(string[] args)
{
var testClassObject = new TestClass();
Console.WriteLine($"{testClassObject.PublicField}");
Console.WriteLine($"{testClassObject.InternalField}");
// Console.WriteLine($"{testClassObject.ProtectedField}");
Console.WriteLine($"{testClassObject.ProtectedInternalField}"); // 같은 어셈블리 안에 있으면 internal처럼 작동
}
}
}
using AccessModifiers1;
using System;
namespace AccessModifierAnotherAssembly
{
internal class Program
{
static void Main(string[] args)
{
var testClassObject = new TestClass();
Console.WriteLine(testClassObject.PublicField);
// Console.WriteLine(testClassObject.InternalField);
}
}
public class ChildOfTheClassFromAnotherAssembly : TestClass // 다른 어셈블리에서 상속
{
public ChildOfTheClassFromAnotherAssembly()
{
Console.WriteLine(base.ProtectedField);
Console.WriteLine(base.ProtectedInternalField); // 상속된 클래스에서 접근 가능
}
}
}
[Private protected 예시 코드]
같은 어셈블리 안에서는 Protected 처럼 작동하지만, 그렇지 않으면 접근할 수 없다.
using System;
namespace AccessModifiers1
{
public class TestClass
{
public string PublicField = "public";
internal string InternalField = "internal";
protected string ProtectedField = "protected";
protected internal string ProtectedInternalField = "protected internal";
private protected string PrivateProtectedField = "private protected";
}
public class ChildOfTestClass : TestClass
{
public ChildOfTestClass()
{
Console.WriteLine(base.ProtectedField);
Console.WriteLine(base.PrivateProtectedField); // PrivateProtected 는 같은 어셈블리 안에서는 Protected 처럼 작동
}
}
class Program
{
public int num1 = 100;
static void Main(string[] args)
{
var testClassObject = new TestClass();
Console.WriteLine($"{testClassObject.PublicField}");
Console.WriteLine($"{testClassObject.InternalField}");
// Console.WriteLine($"{testClassObject.ProtectedField}");
Console.WriteLine($"{testClassObject.ProtectedInternalField}");
// Console.WriteLine($"{testClassObject.PrivateProtectedField}"); // syntax 에러
}
}
}
using AccessModifiers1;
using System;
namespace AccessModifierAnotherAssembly
{
internal class Program
{
static void Main(string[] args)
{
var testClassObject = new TestClass();
Console.WriteLine(testClassObject.PublicField);
// Console.WriteLine(testClassObject.InternalField);
}
}
public class ChildOfTheClassFromAnotherAssembly : TestClass
{
public ChildOfTheClassFromAnotherAssembly()
{
Console.WriteLine(base.ProtectedField);
Console.WriteLine(base.ProtectedInternalField);
// Console.WriteLine(base.PrivateProtectedField); // syntax 에러
}
}
}
[Private 예시 코드]
using System;
namespace AccessModifiers1
{
public class TestClass
{
public string PublicField = "public";
internal string InternalField = "internal";
protected string ProtectedField = "protected";
protected internal string ProtectedInternalField = "protected internal";
private protected string PrivateProtectedField = "private protected";
private string PrivateField = "Private"; // Private
public TestClass()
{
Console.WriteLine(PrivateField); // 클래스 안에 있어야 접근 가능
}
}
public class ChildOfTestClass : TestClass
{
public ChildOfTestClass()
{
Console.WriteLine(base.ProtectedField);
Console.WriteLine(base.PrivateProtectedField);
}
}
class Program
{
public int num1 = 100;
static void Main(string[] args)
{
var testClassObject = new TestClass();
Console.WriteLine($"{testClassObject.PublicField}");
Console.WriteLine($"{testClassObject.InternalField}");
// Console.WriteLine($"{testClassObject.ProtectedField}");
Console.WriteLine($"{testClassObject.ProtectedInternalField}");
// Console.WriteLine($"{testClassObject.PrivateProtectedField}");
}
}
}
댓글남기기