理解C#中的存取修飾符
在本文中,我們將深入探討C#的存取修飾字,它們定義了C#中型別、方法和變數的可見性和可存取性。 Tim Corey在他的影片"C#存取修飾字(不止public和private)—— 它們是什麼,怎麼用,以及最佳實踐"中,解釋了各種存取修飾字並展示了它們在控制台應用程式中的實際用法。
本文將解釋Tim所涵蓋的內容,並提供程式碼範例以加深您的理解。 所提供的時間標記使您可以跟隨影片進行更具有實際動手操作的體驗。
什麼是存取修飾字?
介紹
Tim Corey首先介紹了存取修飾字,解釋它們決定了在C#中誰可以看到和使用資源。 雖然我們熟悉常用的public和private修飾字,但Tim探討了六種不同的存取修飾字及其使用案例。
示範應用程式解釋
Tim設置了一個簡單的應用程式來演示各種存取修飾字的工作原理。 該應用程式由一個控制台使用者介面和一個示範程式庫組成,兩者都在.NET框架中。
專案結構:
- Console UI:一個用於測試存取修飾字的控制台應用程式。
- Demo Library:一個展示不同存取修飾字的類別庫。
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演示了它無法從類別外部存取,即使其他類別在同一個專案中。
最佳實踐:當您希望限制存取類別的內部運作,以確保其不能被應用程式的其他部分直接更改時,請使用私有。
2. 內部(Internal)
它是什麼:
內部修飾字允許方法或屬性僅在同一個元件(專案)內存取。 這比私有存取修飾字更廣泛,因為它包括所有同一個專案中的類別。
程式碼範例:
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 方法可以被同一個元件中的任何類別存取,但不能從其他元件存取。 在影片中,Tim展示了內部修飾字允許內部專案中存取,但拒絕來自外部的存取。
最佳實踐:當方法或屬性僅供當前元件使用時,請使用內部修飾字,如不應暴露給外部專案的輔助功能或實用工具。
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示範了公開是最常見的存取修飾字,特別是在公開方法在庫中時。
最佳實踐:當方法或屬性需要由應用程式的其他部分或外部專案存取時,請使用公開修飾字,如API端點或廣泛使用的實用工具。
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解釋說,受保護雖然不常見,但在處理繼承時非常有用。
最佳實踐:當您希望允許派生類別存取特定的方法或屬性,但不希望它們被類別層階之外所存取時,請使用受保護修飾字。
5. 私有受保護(Private 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 方法可以在 DerivedClass 中存取,因為它繼承自 AccessDemo 並且存在於同一個元件中。 然而,它不能在 UnrelatedClass 中存取,因為這個類不繼承自 AccessDemo。
最佳實踐:當您需要緊密控制同一個元件內的繼承存取時,請謹慎使用私有受保護存取修飾字。 這在方法或屬性暴露於跨元件可能會損害封裝的情況中特別有用。
6. 受保護內部(Protected Internal)
它是什麼:
受保護內部修飾字結合了受保護和內部存取修飾字的級別。 它允許從同一個元件或派生類別中存取,即使它們位於不同的元件。
程式碼範例:
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 方法可以在同一個元件內以及來自任何派生類中存取,不論它們在何元件中。
最佳實踐:當您希望將方法公開給派生類(其他元件中)和同一個元件中的類別,但不希望將其公開給每個人時,請使用受保護內部。
為什麼不將一切設為公開?
Tim Corey解釋了使用存取修飾字的重要性以及為什麼不應該將所有內容設為公開。 雖然將所有內容設為公開看起來方便,但這會帶來重大風險,包括資料洩漏、漏洞和開發中的混亂。 存取修飾字的存在是為了安全資訊、防止無意的公眾存取,並提供程式碼庫的清晰性。
1. 保護私人資訊
Tim討論了為什麼敏感資訊,如社會安全號碼(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\ Tim解釋說,私有方法有助於封裝不應直接存取的行為。 他使用了 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. 防止漏洞
存取修飾字通過確保資料在適當的驗證下設置或檢索來防止漏洞。 Tim用涉及 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
}
}通過正確地使用這些存取修飾字,您可以使您的工作和下一個人的工作更輕鬆。
結論
Tim Corey提供了一份清晰而實用的指南來掌握C#存取修飾字,並展示了如何有效地使用它們來建立安全的、可維護的、專業的應用程式。 他詳細的解釋和真實世界的例子使這個話題對所有級別的開發者都很容易理解。
欲獲得更深入的見解並觀看這些概念的實際應用,一定要觀看Tim的完整影片,並探索他的頻道,以獲取有關C#及其他程式設計主題的寶貴內容。 這是任何認真提升開發技巧的人必訪之地!

