理解 C# 訪問修飾符
在本文中,我們將深入探討C#存取修飾詞,這些修飾詞定義了類型、方法和變數在C#中的可見性和可訪問性。 Tim Corey 在他的影片 "C# 存取修飾詞(超越公有與私有)- 它們是什麼、如何使用和最佳實踐" 中,解釋了各種存取修飾詞,並展示了它們在控制台應用中的實際使用。
本文將解釋 Tim 涵蓋的內容,以及提供代碼範例以增強您的理解。 所提供的時間戳允許您與影片同步進行,獲得更實用的體驗。
什麼是存取修飾詞?
介紹
Tim Corey 開始介紹存取修飾詞,解釋這些修飾詞決定了在 C# 中誰可以看到和使用資源。 雖然我們熟悉常用的公有和私有修飾詞,Tim 探討了六種不同的存取修飾詞及其使用情境。
演示應用程序說明
Tim 設置了一個簡單的應用程序來演示各種存取修飾詞的工作原理。 該應用程序由控制台用戶界面和演示庫組成,兩者都在 .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 演示了無法從類外訪問,即使其他類在同一專案中。
最佳實踐:當您希望限制對類內部工作的存取時使用私有,以確保其不能從應用程序的其他部分直接修改。
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#和其他編程主題的寶貴內容。 這是任何認真提升編程技能的人絕對必須訪問的資源!
