6 Access Modifiers trong C#
| Modifier | Phạm vi truy cập | Keyword |
| public | Bất kỳ đâu (unrestricted) | public |
| private | Chỉ trong class/struct khai báo | private |
| protected | Class khai báo + derived classes | protected |
| internal | Chỉ trong cùng assembly (project) | internal |
| protected internal | Cùng assembly HOẶC derived class (union) | protected internal |
| private protected | Cùng assembly VÀ derived class (intersection) | private protected |
Chi tiết từng Modifier
1. public - Mở hoàn toàn
public class Person
{
public string Name = "Mark"; // Truy cập từ đâu cũng được
}
// Assembly khác
var p = new Person();
Console.WriteLine(p.Name); // OK
2. private - Đóng kín nhất
public class Person
{
private string _ssn = "123-45-6789"; // Chỉ truy cập trong Person
public string GetMaskedSsn() => "***-**-" + _ssn.Substring(7);
}
// Assembly khác
var p = new Person();
// p._ssn; // ❌ Compile error
Console.WriteLine(p.GetMaskedSsn()); // OK
3. protected - Cho kế thừa
public class Person
{
protected string Name = "Mark"; // Class con truy cập được
}
public class Employee : Person
{
public void Print() => Console.WriteLine(Name); // OK
}
public class Program
{
static void Main()
{
var e = new Employee();
e.Print(); // OK: Mark
var p = new Person();
// p.Name; // ❌ Compile error - không phải derived class
}
}
4. internal - Assembly boundary
// Project MyLibrary (Assembly A)
public class InternalService
{
internal void DoWork() { } // Chỉ Assembly A truy cập được
}
// Project MyApp (Assembly B) - reference MyLibrary
var svc = new InternalService();
// svc.DoWork(); // ❌ Compile error: inaccessible due to protection level
5. protected internal - Union (OR)
// Assembly A
public class Base
{
protected internal string Data = "Secret";
}
// Assembly A - Same assembly
class SameAssembly
{
void Test()
{
var b = new Base();
Console.WriteLine(b.Data); // OK - same assembly
}
}
// Assembly B - Derived class
public class DerivedInOtherAssembly : Base
{
void Test()
{
Console.WriteLine(Data); // OK - derived class
}
}
// Assembly B - Non-derived
class Unrelated
{
void Test()
{
var b = new Base();
// b.Data; // ❌ Error - khác assembly KHÔNG phải derived
}
}
6. private protected - Intersection (AND) - C# 7.2+
// Assembly A
public class Base
{
private protected string Secret = "Top Secret";
}
// Assembly A - Derived class
class DerivedInSameAssembly : Base
{
void Test() => Console.WriteLine(Secret); // OK: same assembly AND derived
}
// Assembly A - Non-derived
class UnrelatedInSameAssembly
{
void Test()
{
var b = new Base();
// b.Secret; // ❌ Error - không phải derived
}
}
// Assembly B - Derived class
public class DerivedInOtherAssembly : Base
{
void Test()
{
// Console.WriteLine(Secret); // ❌ Error - khác assembly
}
}
Accessibility Matrix (Quick Reference)
| Same Type | Derived Same Asm | Non-Derived Same Asm | Derived Diff Asm | Non-Derived Diff Asm |
| public | ✅ | ✅ | ✅ | ✅ | ✅ |
| protected internal | ✅ | ✅ | ✅ | ✅ | ❌ |
| protected | ✅ | ✅ | ❌ | ✅ | ❌ |
| internal | ✅ | ✅ | ✅ | ❌ | ❌ |
| private protected | ✅ | ✅ | ❌ | ❌ | ❌ |
| private | ✅ | ❌ | ❌ | ❌ | ❌ |
Best Practices
- Default: private - Encapsulation, chỉ public khi cần thiết.
- Public API:
public cho types/members công khai.
- Internal: Implementation details trong assembly (helpers, DTOs nội bộ).
- Protected: Base class members dành cho derived class override.
- Protected internal: Hiếm dùng - khi muốn derived class ở assembly khác truy cập.
- Private protected: Rất hiếm - base class internal implementation cho derived trong cùng assembly.
Class/Struct Accessibility
// Top-level types: chỉ public hoặc internal
public class PublicClass { } // Visible outside assembly
internal class InternalClass { } // Chỉ trong assembly (default nếu không viết)
// Nested types: có thể dùng tất cả 6 modifiers
public class Outer
{
private class PrivateNested { }
protected class ProtectedNested { }
internal class InternalNested { }
protected internal class ProtIntNested { }
private protected class PrivProtNested { }
public class PublicNested { }
}