字段:
“字段”是直接在 类或 结构中声明的任何类型的变量。
字段是其包含类型的“成员”。
类或结构可以拥有实例字段或静态字段,或同时拥有两者。
实例字段特定于类型的实例。
如果您拥有类 T 和实例字段 F,可以创建类型 T 的两个对象,并修改每个对象中 F 的值,这不影响另一对象中的该值。
相比之下,静态字段属于类本身,在该类的所有实例中共享。
从实例 A 所做的更改将立刻呈现在实例 B 和 C 上(如果它们访问该字段)。
通常应仅为具有私有或受保护可访问性的变量使用字段。
您的类向客户端代码公开的数据应通过 方法、 属性和 索引器提供。
通过使用这些构造间接访问内部字段,可以针对无效的输入值提供防护。
存储由公共属性公开的数据的私有字段称为“后备存储”或“支持字段”。
字段通常存储这样的数据:该数据必须可供多个类方法访问,并且其存储期必须长于任何单个方法的生存期。
例如,表示日历日期的类可能有三个整数字段:一个表示月份,一个表示日期,还有一个表示年份。
不在单个方法范围外部使用的变量应在方法体自身范围内声明为局部变量。
在类块中通过指定字段的访问级别,然后指定字段的类型,再指定字段的名称来声明这些字段。
例如:
public class CalendarEntry
{
// private field
private DateTime date;
// public field (Generally not recommended.)
public string day;
// Public property exposes date field safely.
public DateTime Date
{
get
{
return date;
}
set
{
// Set some reasonable boundaries for likely birth dates.
if (value.Year > 1900 && value.Year <= DateTime.Today.Year)
{
date = value;
}
else
throw new ArgumentOutOfRangeException();
}
}
// Public method also exposes date field safely.
// Example call: birthday.SetDate("1975, 6, 30");
public void SetDate(string dateString)
{
DateTime dt = Convert.ToDateTime(dateString);
// Set some reasonable boundaries for likely birth dates.
if (dt.Year > 1900 && dt.Year <= DateTime.Today.Year)
{
date = dt;
}
else
throw new ArgumentOutOfRangeException();
}
public TimeSpan GetTimeSpan(string dateString)
{
DateTime dt = Convert.ToDateTime(dateString);
if (dt != null && dt.Ticks < date.Ticks)
{
return date - dt;
}
else
throw new ArgumentOutOfRangeException();
}
}
常量:
常量是在编译时已知并在程序的生存期内不发生更改的不可变值。
常量使用 const 修饰符进行声明。
只有 C# 内置类型( System ..::. Object 除外)可以声明为 const。
有关内置类型的列表,请参见 内置类型表(C# 参考)。
用户定义的类型(包括类、结构和数组)不能为 const。
请使用 readonly 修饰符创建在运行时初始化一次即不可再更改的类、结构或数组。
C# 不支持 const 方法、属性或事件。
可以使用枚举类型为整数内置类型(例如 int、 uint、 long 等等)定义命名常量。
有关更多信息,请参见 enum(C# 参考)。
常量必须在声明时初始化。
例如:
class Calendar1
{
public const int months = 12;
}
属性:
属性是这样的成员:它提供灵活的机制来读取、编写或计算某个私有字段的值。
可以像使用公共数据成员一样使用属性,但实际上它们是称作“访问器”的特殊方法。
这使得可以轻松访问数据,此外还有助于提高方法的安全性和灵活性。
在本示例中, TimePeriod 类存储一个时间段。
在内部,类以秒为单位存储时间,但客户端使用名为 Hours 的属性能够以小时为单位指定时间。
Hours 属性的访问器执行小时和秒之间的转换。
class TimePeriod
{
private double seconds;
public double Hours
{
get { return seconds / 3600; }
set { seconds = value * 3600; }
}
}
class Program
{
static void Main()
{
TimePeriod t = new TimePeriod();
// Assigning the Hours property causes the 'set' accessor to be called.
t.Hours = 24;
// Evaluating the Hours property causes the 'get' accessor to be called.
System.Console.WriteLine("Time in hours: " + t.Hours);
}
}
// Output: Time in hours: 24
属性概述
这些访问器可以有不同的访问级别。
有关更多信息,请参见 限制访问器可访问性(C# 编程指南)。
有关更多信息,请参见 自动实现的属性(C# 编程指南)。
方法:
“方法”是包含一系列语句的代码块。
程序通过“调用”方法并指定所需的任何方法参数来执行语句。
在 C# 中,每个执行指令都是在方法的上下文中执行的。
Main 方法是每个 C# 应用程序的入口点,在启动程序时由公共语言运行时 (CLR) 调用。
方法签名
通过指定方法的访问级别(例如 public 或 private)、可选修饰符(例如 abstract 或 sealed)、返回值、名称和任何方法参数,可以在 类或 结构中声明方法。
这些部分统称为方法的“签名”。
注意:为进行方法重载,方法的返回类型不是方法签名的一部分。但是,在确定委托和委托所指向方法之间的兼容性时,返回类型是方法签名的一部分。
方法参数括在括号中,并用逗号隔开。
空括号表示方法不需要参数。
方法访问
在对象上调用方法类似于访问字段。
在对象名称之后,依次添加句点、方法名称和括号。
参数在括号内列出,并用逗号隔开。
方法参数和实参
方法定义指定所需任何“形参”的名称和类型。
调用代码在调用方法时,将为每个形参提供称为“实参”的具体值。
实参必须与形参类型兼容,但调用代码中使用的实参名称(如果有)不必与方法中定义的形参名称相同。
通过引用传递与通过值传递
默认情况下,将值类型传递给方法时,传递的是副本而不是对象本身。
因此,对参数所做的更改对于调用方法中的原始副本没有影响。
可以使用 ref 关键字通过引用传递值类型。
有关更多信息,请参见 传递值类型参数(C# 编程指南)。
有关内置值类型的列表,请参见 值类型表(C# 参考)。
“引用类型”通过引用进行传递。
将引用类型的对象传递给方法时,引用指向原始对象而不是副本。
因此,通过此引用所进行的更改将反映在调用方法中。
返回值
方法可以向调用方返回值。
如果返回类型(方法名称前列出的类型)不是 void,则方法可以使用 return 关键字来返回值。
如果语句中 return 关键字的后面是与返回类型匹配的值,则该语句将该值返回给方法调用方。
return 关键字还会停止方法的执行。
如果返回类型为 void,则可使用没有值的 return 语句来停止方法的执行。
如果没有 return 关键字,方法执行到代码块末尾时即会停止。
具有非 void 返回类型的方法才能使用 return 关键字返回值。
构造函数:
任何时候,只要创建 类或 结构,就会调用它的构造函数。
类或结构可能有多个接受不同参数的构造函数。
构造函数使得程序员可设置默认值、限制实例化以及编写灵活且便于阅读的代码。
如果您没有为对象提供构造函数,则默认情况下 C# 将创建一个构造函数,该构造函数实例化对象,并将成员变量设置为 默认值表(C# 参考)中列出的默认值。
静态类和结构也可以有构造函数。
使用构造函数
构造函数是在创建给定类型的对象时执行的 类方法。
构造函数具有与类相同的名称,它通常初始化新对象的数据成员。
在下面的示例中,使用一个简单的构造函数定义了名为 Taxi 的类。
然后使用 new 运算符来实例化该类。
在为新对象分配内存之后, new 运算符立即调用 Taxi 构造函数。
public class Taxi
{
public bool isInitialized;
public Taxi()
{
isInitialized = true;
}
}
class TestTaxi
{
static void Main()
{
Taxi t = new Taxi();
Console.WriteLine(t.isInitialized);
}
}
不带参数的构造函数称为“默认构造函数”。
无论何时,只要使用 new 运算符实例化对象,并且不为 new 提供任何参数,就会调用默认构造函数。
实例构造函数
使用 new 表达式创建某个 类的对象时,会使用实例构造函数创建和初始化所有实例成员变量。
要初始化 静态类或非静态类中的静态变量,必须定义静态构造函数。
私有构造函数
私有构造函数是一种特殊的实例构造函数。
它通常用在只包含静态成员的类中。
如果类具有一个或多个私有构造函数而没有公共构造函数,则其他类(除嵌套类外)无法创建该类的实例。
静态构造函数
静态构造函数用于初始化任何 静态 数据,或用于执行仅需执行一次的特定操作。
在创建第一个实例或引用任何静态成员之前,将自动调用静态构造函数。
析构函数:
析构函数用于析构类的实例。
备注
只能对类使用析构函数。
它们是被自动调用的。
例如,下面是类 Car 的析构函数的声明:
class Car
{
~Car() // destructor
{
// cleanup statements...
}
}
该析构函数隐式地对对象的基类调用 Finalize。
这样,前面的析构函数代码被隐式地转换为以下代码:
protected override void Finalize()
{
try
{
// Cleanup statements...
}
finally
{
base.Finalize();
}
}
protected override void Finalize()
{
try
{
// Cleanup statements...
}
finally
{
base.Finalize();
}
}
这意味着对继承链中的所有实例递归地调用 Finalize 方法(从派生程度最大的到派生程度最小的)。
注意
不应使用空析构函数。
如果类包含析构函数, Finalize 队列中则会创建一个项。
调用析构函数时,将调用垃圾回收器来处理该队列。
如果析构函数为空,只会导致不必要的性能损失。
使用析构函数释放资源
通常,与运行时不进行垃圾回收的开发语言相比,C# 无需太多的内存管理。
这是因为 .NET Framework 垃圾回收器会隐式地管理对象的内存分配和释放。
但是,当应用程序封装窗口、文件和网络连接这类非托管资源时,应当使用析构函数释放这些资源。
当对象符合析构时,垃圾回收器将运行对象的 Finalize 方法。