访问修饰符
可以限制类和结构,以便只有声明它们的程序或命名空间才能使用它们。可以限制类成员,以便只有派生类才能使用它们,或者限制类成员,以便只有当前命名空间或程序中的类才能使用它们。访问修饰符是添加到类、结构或成员声明的关键字,用以指定这些限制。这些关键字包括 public、private、protected 和 internal。访问修饰符不影响类或结构自身 -- 它始终能够访问自身及其所有成员。
public :声明为公共的类型可由任何其他类型访问
private : 将类成员或结构成员声明为私有的,指示只有声明该成员的类或结构才能访问该成员。
protected : 将类成员声明为受保护的,意味着只有使用该类作为基类的派生类型才能访问该成员。
internal:声明为内部的类型只能由同一程序集中的类型访问,类和结构默认声明为内部的。
![ContractedBlock.gif](/Images/OutliningIndicators/ContractedBlock.gif)
![ExpandedBlockStart.gif](/Images/OutliningIndicators/ExpandedBlockStart.gif)
public class Tricycle
{
// protected method:
protected void Pedal() { }
// private field:
private int m_wheels = 3 ;
// protected internal property:
protected internal int Wheels
{
get { return m_wheels; }
}
}
其他类型的访问修饰符
与类一样,接口也可声明为公共类型或内部类型。与类不同,接口默认具有内部访问级别。接口成员始终是公共的,不能应用任何访问修饰符。
命名空间和枚举成员始终是公共的,不能应用任何访问修饰符。
委托默认具有内部访问级别。
默认情况下,在命名空间中或在编译单元顶部(例如,不在命名空间、类或结构中)声明的任何类型都是内部的,但是可以成为公共的。
“方法”是包含一系列语句的代码块。在 C# 中,每个执行指令都是在方法的上下文中完成的。
方法在类或结构中声明,声明时,声明时需要指定访问级别、返回值、方法名称以及任何方法参数。方法参数放在括号中,并用逗号隔开。空括号表示方法不需要参数。下面的类包含三个方法:
{
public void StartEngine() { }
public void AddGas( int gallons) { }
public int Drive( int miles, int speed) { return 0 ; }
}
与字段不同,属性不作为变量来分类。因此,不能将属性作为 ref(C# 参考)参数或 out(C# 参考)参数传递。
属性具有多种用法:它们可在允许更改前验证数据;它们可透明地公开某个类上的数据,该类的数据实际上是从其他源(例如数据库)检索到的;当数据被更改时,它们可采取行动,例如引发事件或更改其他字段的值。
{
private int month = 7 ; // "backing store"
public int Month
{
get
{
return return month!= null ? month: 7;
}
set
{
if ((value > 0 ) && (value < 13 ))
{
month = value;
}
}
}
}
在 set 访问器中,对局部变量声明使用隐式参数名称 value 是错误的。
可将属性标记为 public、private、protected、internal 或 protected internal。这些访问修饰符定义类的用户如何才能访问属性。同一属性的 get 和 set 访问器可能具有不同的访问修饰符。例如,get 可能是 public 以允许来自类型外的只读访问;set 可能是 private 或 protected。
可以使用 static 关键字将属性声明为静态属性。这使得调用方随时可使用该属性,即使不存在类的实例。
可以使用 virtual 关键字将属性标记为虚属性。这样,派生类就可以使用 override 关键字来重写属性行为。
重写虚属性的属性还可以是 sealed 的,这表示它对派生类不再是虚拟的。最后一点,属性可以声明为 abstract,这意味着在类中没有实现,派生类必须编写自己的实现
对 static 属性的访问器使用 virtual(C# 参考)、abstract(C# 参考)或 override(C# 参考)修饰符是错误的。
要声明类或结构上的索引器,请使用 this 关键字,如下例所示:
public int this[int index] // Indexer declaration { // get and set accessors }
索引器类型及其参数类型必须至少如同索引器本身一样是可访问的
索引器的签名由其形参的数量和类型组成。它不包括索引器类型或形参名。如果在同一类中声明一个以上的索引器,则它们必须具有不同的签名。
索引器值不归类为变量;因此,不能将索引器值作为 ref 或 out 参数来传递。
要为索引器提供一个其他语言可以使用的名字,请使用声明中的 name
属性。例如:
[System.Runtime.CompilerServices.CSharp.IndexerName("TheItem")] public int this [int index] // Indexer declaration { }
此索引器将具有名称 TheItem
。不提供名称属性将生成 Item
默认名称。
{
private int [] arr = new int [ 100 ];
public int this [ int index] // Indexer declaration
{
get
{
// Check the index limits.
if (index < 0 || index >= 100 )
{
return 0 ;
}
else
{
return arr[index];
}
}
set
{
if ( ! (index < 0 || index >= 100 ))
{
arr[index] = value;
}
}
}
}
class MainClass
{
static void Main()
{
IndexerClass test = new IndexerClass();
// Call the indexer to initialize the elements #3 and #5.
test[ 3 ] = 256 ;
test[ 5 ] = 1024 ;
for ( int i = 0 ; i <= 10 ; i ++ )
{
System.Console.WriteLine( " Element #{0} = {1} " , i, test[i]);
}
}
}
使用其他值进行索引
C# 并不将索引类型限制为整数。例如,对索引器使用字符串可能是有用的。通过搜索集合内的字符串并返回相应的值,可以实现此类的索引器。由于访问器可被重载,字符串和整数版本可以共存。
![ContractedBlock.gif](/Images/OutliningIndicators/ContractedBlock.gif)
![ExpandedBlockStart.gif](/Images/OutliningIndicators/ExpandedBlockStart.gif)
// Using a string as an indexer value
class DayCollection {
string[] days = { "Sun", "Mon", "Tues", "Wed", "Thurs", "Fri", "Sat" };
// This method finds the day or returns -1
private int GetDay(string testDay)
{
int i = 0;
foreach (string day in days)
{
if (day == testDay)
{
return i;
}
i++;
}
return -1;
}
// The get accessor returns an integer for a given string
public int this[string day]
{
get{ return (GetDay(day)); }
}
}
class Program {
static void Main(string[] args)
{
ayCollection week = new DayCollection();
System.Console.WriteLine(week["Fri"]);
System.Console.WriteLine(week["Made-up Day"]);
}
}
提高索引器的安全性和可靠性有两种主要的方法:
-
当设置并检索来自索引器访问的任何缓冲区或数组的值时,请始终确保您的代码执行范围和类型检查。
-
应当为 get 和 set 访问器的可访问性设置尽可能多的限制。这一点对 set 访问器尤为重要。