C#類訪問修飾符
訪問修飾符是一些關鍵字,用於指定宣告的成員或型別的可訪問性。訪問修飾符有四個:
public protected internal private
宣告的可訪問性 | 含義 |
public | 訪問不受限制。 |
protected | 訪問僅限於包含類或從包含類派生的型別。 |
internal | 訪問僅限於當前程式集。 |
protected internal | 訪問僅限於從包含類派生的當前程式集或型別。 |
private | 訪問僅限於包含型別。 |
一個成員或型別只能有一個訪問修飾符,使用 protected internal 組合時除外。
名稱空間上不允許使用訪問修飾符。名稱空間沒有訪問限制。
根據發生成員宣告的上下文,只允許某些宣告的可訪問性。如果在成員宣告中未指定訪問修飾符,則使用預設的可訪問性。
不巢狀在其他型別中的頂級型別的可訪問性只能是 internal 或 public。這些型別的預設可訪問性是 internal。
巢狀型別是其他型別的成員,它們可以具有下表所示的宣告的可訪問性。
屬於 | 預設的成員可訪問性 | 該成員允許的宣告的可訪問性 |
enum | public | 無 |
class | private | public protected internal private protected internal |
interface | public | 無 |
struct | private | public internal private |
範例如下:
publicTest
namespace publicTest
{
class Point
{
public int x;
//private int x;
//protected int x;
//internal int x;
public int y;
}
}
namespace publicTest
{
class MainClass
{
static void Main()
{
Point p = new Point();
// Direct access to public members:
p.x = 10;
p.y = 15;
Console.WriteLine("x = {0}, y = {1}", p.x, p.y);
Console.ReadLine();
}
}
}
在同一程式集下,定義Point類下的成員為public與internal,可直接通過 MainClass 訪問 Point 的公共成員 x 和 y。
protectedTest
namespace protectedTest
{
class A
{
protected int x = 123;
//public int x = 123;
}
}
namespace protectedTest
{
class B : A
{
static void Main()
{
A a = new A();
B b = new B();
// Error CS1540, because x can only be accessed by
// classes derived from A.
// a.x = 10;
// OK, because this class derives from A.
b.x = 10;
//Console.WriteLine("{0} {1}", a.x, b.x);
Console.WriteLine(b.x);
Console.ReadLine();
}
}
}
在B中呼叫類A的建構函式,建立一個物件a。然後獲取a.x會報CS1540錯誤,在網上也搜了好久。搜到瞭如下資訊:protected型別並不是能夠被派生類隨心所欲的訪問,而是有條件的,訪問必須是通過派生類型別發生時,在派生類中的基類的protected型別成員才能夠被訪問,這裡就很清楚了上面的程式碼並不是通過派生類的型別訪問的,而是通過基類的型別訪問的,此時此刻,protected和private十分的相似,只不過,protected型別成員能夠被派生類所繼承並且能夠通過派生類型別訪問罷了。
namespace protectedTest
{
class Point
{
protected int x;
protected int y;
}
}
namespace protectedTest
{
class DerivedPoint : Point
{
static void Main()
{
DerivedPoint dp = new DerivedPoint();
// Direct access to protected members:
dp.x = 10; dp.y = 15;
Console.WriteLine("x = {0}, y = {1}", dp.x, dp.y);
Console.ReadLine();
}
}
}
privateTest
namespace privateTest
{
class Employee
{
private string name = "FirstName, LastName";
private double salary = 100.0;
public string GetName()
{
return name;
}
public double Salary
{
get { return salary; }
}
}
}
namespace privateTest
{
class MainClass
{
static void Main()
{
Employee e = new Employee();
// The data members are inaccessible (private), so
// then can't be accessed like this:
//string n = e.name;
//double s = e.salary;
// 'name' is indirectly accessed via method:
string n = e.GetName();
// 'salary' is indirectly accessed via property
double s = e.Salary;
Console.WriteLine("{0} {1}",n,s);
Console.ReadLine();
}
}
}
MainClass無法直接訪問物件的name和salary成員,需要屬性或者方法。C#的類有field(欄位)和Attribute(屬性)。欄位用小寫,並且是不對外暴露,也就是說是私有或者是保護變數(id)。外部如果要操作(讀、寫)這些欄位,需要通過對外暴露出來的屬性(ID)的get(讀)、set(寫)操作。
internalTest
namespace internalTest
{
internal class BaseClass
{
public static int intM = 0;
}
//public class BaseClass
//{
// public static int intM = 0;
//}
}
namespace Assembly
{
class TestAccess
{
static void Main()
{
BaseClass myBase = new BaseClass(); // CS0122
}
}
}
不在一個程式集中, “internalTest.BaseClass.BaseClass()”不可訪問,因為它受保護級別限制。
使用public
namespace internalTest
{
public class BaseClass_B
{
internal static int intM = 0;
}
}
namespace Assembly
{
public class TestAccess_B
{
static void Main()
{
BaseClass_B myBase = new BaseClass_B(); // Ok.
myBase.intM = 444; // CS0117
}
}
}
會報出錯誤:無法使用例項引用來訪問成員“internalTest.BaseClass_B.intM”;請改用型別名來限定它,因為intM在internalTest中為靜態方法。
靜態成員也稱為共享成員,例如靜態屬性 靜態欄位 靜態方法;靜態成員可以在類的例項之間共享。靜態類中只能有靜態成員,不能有例項成員,因為靜態類不能進行例項化;在非靜態類中即可以有靜態成員也可以有非靜態成員;只要是靜態成員 屬性 欄位 方法,都需要用類名去呼叫;當類第一次載入的時候(第一次被載入到記憶體的時候),該類下的所有的靜態成員都會被載入,例項成員有多少個物件,就會建立多少個物件;靜態成員會被載入到靜態儲存區,直到程式退出時才會被釋放;
修改後程式碼:
namespace Assembly
{
public class TestAccess_B
{
static void Main()
{
BaseClass_B myBase_B = new BaseClass_B(); // Ok.
BaseClass_B.intM = 444;
}
}
}