C#语言规范5.0中对字段的解释:
字段是与类或类的实例关联的变量。
使用 static 修饰符声明的字段定义了一个静态字段 (static field)。一个静态字段只标识一个存储位置。无论对一个类创建多少个实例,它的静态字段永远都只有一个副本。
不使用 static 修饰符声明的字段定义了一个实例字段 (instance field)。类的每个实例都为该类的所有实例字段包含一个单独副本。
在下面的示例中,Color 类的每个实例都有实例字段 r、g 和 b 的单独副本,但是 Black、White、Red、Green 和 Blue 静态字段只存在一个副本:
public class Color
{
public static readonly Color Black = new Color(0, 0, 0);
public static readonly Color White = new Color(255, 255, 255);
public static readonly Color Red = new Color(255, 0, 0);
public static readonly Color Green = new Color(0, 255, 0);
public static readonly Color Blue = new Color(0, 0, 255);
private byte r, g, b;
public Color(byte r, byte g, byte b) {
this.r = r;
this.g = g;
this.b = b;
}
}
如上面的示例所示,可以使用 readonly 修饰符声明只读字段 (read-only field)。给 readonly 字段的赋值只能作为字段声明的组成部分出现,或在同一个类中的构造函数中出现。
1.6.7.2 属性
属性 (property) 是字段的自然扩展。
属性和字段都是命名的成员,都具有相关的类型,且用于访问字段和属性的语法也相同。然而,与字段不同,属性不表示存储位置。相反,属性有访问器 (accessor),这些访问器指定在它们的值被读取或写入时需执行的语句。
属性的声明与字段类似,不同的是属性声明以位于定界符 { 和 } 之间的一个 get 访问器和/或一个 set 访问器结束,而不是以分号结束。同时具有 get 访问器和 set 访问器的属性是读写属性 (read-write property),只有 get 访问器的属性是只读属性 (read-only property),只有 set 访问器的属性是只写属性 (write-only property)。
get 访问器相当于一个具有属性类型返回值的无形参方法。除了作为赋值的目标,当在表达式中引用属性时,将调用该属性的 get 访问器以计算该属性的值。
set 访问器相当于具有一个名为 value 的参数并且没有返回类型的方法。当某个属性作为赋值的目标被引用,或者作为 ++ 或 -- 的操作数被引用时,将调用 set 访问器,并传入提供新值的实参。
List<T> 类声明了两个属性 Count和 Capacity,它们分别是只读属性和读写属性。下面是这些属性的使用示例。
List<string> names = new List<string>();
names.Capacity = 100; // Invokes set accessor
int i = names.Count; // Invokes get accessor
int j = names.Capacity; // Invokes get accessor
与字段和方法相似,C# 同时支持实例属性和静态属性。静态属性使用 static 修饰符声明,而实例属性的声明不带该修饰符。
属性的访问器可以是虚的。当属性声明包括 virtual、abstract 或 override 修饰符时,修饰符应用于该属性的访问器。
————————————————————————————
字段与属性的区别
在C#中,我们可以非常自由的、毫无限制的访问公有字段,但在一些场合中,我们可能希望限制只能给字段赋于某个范围的值、或是要求字段只能读或只能写,或是在改变字段时能改变对象的其他一些状态,这些单靠字段是无法做到的,于是就有了属性,属性中包含两个块:set和get,set块负责属性的写入工作,get块负责属性的读取工作。在两个块中都可以做一些其他操作,如在set中验证赋的值是否符合要求并决定是否进行赋值。当缺少其中一块时属性就只能读或只能写,set和get块中属性必需有一个,因为即不能读又不能写的属性是没有意义的。
class MyClass
{
Private string name;
public string Name
{
get {return Name;}
set {Name=value;}
}
}
(1)属性可以保证安全,当不在本类中使用时可以保证使用属性名可以避免
用字段的名字。
(2)属性的set和get函数可以限制字段的一些功能,以达到某种目的。
如:
private int a=0;
public int A
{
get{return this.a;}
set
{
if(value >= 0 && value <= 100)
this.a=value;
else
throw new Exception("值的范围不合法。");
}
}
(3)属性没有存储数据的功能,数据都存在字段中,所以只有修改字段的数据才能更改数据,修改属性的值没用。
------------------------------------
字段与属性的使用
一般情况下,是先定义字段,再用属性控制赋值的范围。示例代码如下:
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace Example3_2
{
public class Person //定义Person类
{
public string Name { get; set; } //
}
public class Student
{
//public string Name { get; set; }
//public int Age { get; set; }
//姓名
string name;
public string Name
{
get { return this.name; }
set
{
if (value == "")
{
throw new ArgumentException("姓名不能为空字符串。");
}
this.name = value;
}
}
//年龄
private int age;
public int Age
{
get { return this.age; }
set
{
if (value < 1 || value > 100)
{
throw new ArgumentException("年龄超出了有效范围。");
}
this.age = value;
}
}
}
class Program
{
static void Main(string[] args)
{
Student stu = new Student();
stu.Name = "章三";
stu.Age = 56;
Console.WriteLine("姓名是:{0}", stu.Name);
Console.WriteLine("年龄是:{0}", stu.Age);
Console.ReadKey();
}
}
}
运行结果如下:
如果属性只不需要特殊验证处理,可以使用简化的属性声明语法。直接写属性,不写字段。
例如:
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace Example3_2
{
public class Person //定义Person类
{
public string Name { get; set; } //
}
public class Student
{
public string Name { get; set; }
public int Age { get; set; }
}
class Program
{
static void Main(string[] args)
{
Student stu = new Student();
stu.Name = "章三";
stu.Age = 56;
Console.WriteLine("姓名是:{0}", stu.Name);
Console.WriteLine("年龄是:{0}", stu.Age);
Console.ReadKey();
}
}
}
运行结果相同。