溺水动物的C#学习笔记: 字段(Field)与属性(Property)
字段
字段(Field)是在类和结构中声明的任意类型的变量.
class Application {
public int a;
}
如上的示例代码中, public int a
就是一个字段.
声明一个字段的语法规则如下:
其中含有opt下标的都是可选的.
attribute: 特性. 如果您想了解特性请参阅此处
field-modifier: 字段修饰符. 字段修饰符包括new, public, protected, private, internal, readonly, volatile.
您可以使用一个以上的字段修饰符, 但是要注意这些修饰符之间不可以互相冲突.
下面简介一下这些修饰符:
-
new
: 使用new修饰符可以显式隐藏基类的成员. 这样如果您在某个类中定义一个和基类同名的字段, 将不会引起报错或者警告. -
public
,private
,protected
,internal
,都是访问修饰符. 它们修饰这个字段的可见性. -
readonly
, 只读变量, 可以通过构造函数来改变它的值. -
volatile
, 该关键字指示一个字段可以由多个同时执行的线程修改。出于性能原因,编译器,运行时系统甚至硬件都可能重新排列对存储器位置的读取和写入。声明为 volatile 的字段将从某些类型的优化中排除。不确保从所有执行线程整体来看时所有易失性写入操作均按执行顺序排序。
type: 类型.
属性
属性是字段功能的扩展. 我们考虑如下的例子:
using System;
class PeopleAge {
public int age;
static public double CalAverage (params PeopleAge[] x) {
double sum = 0;
foreach(PeopleAge i in x) {
sum += i.age;
}
return sum/ x.Length;
}
}
class Application {
public static void Main(String[] args) {
PeopleAge a = new PeopleAge();
PeopleAge b = new PeopleAge();
PeopleAge c = new PeopleAge();
a.age = 30;
b.age = 1999;
c.age = 80;
Console.WriteLine(PeopleAge.CalAverage(a, b, c));
}
}
这一例我们试图计算三个人类的平均年龄, 但是我们计算出来的年龄是703, 显然是比较扯淡的. 这是由于我们字段中存储的"人类年龄数据"被一个显然不合理的数据"1999"污染了. 所以字段是不够安全的. 当使用字段时, 应当将他们声明为private或者protected.
那么在类之外我们应当如何访问它们? 答案是通过包含访问器声明的属性.
这是一个包含了get和set访问器声明的属性
public class Person
{
public string? FirstName { get; set; }
}
这样写编译器会自动帮你找支持这个定义的字段储存位置, 也会帮你自动生成正文. 如果你想要显式指定, 请使用如下语法:
public class Person
{
public string? FirstName
{
get => _firstName;
set => _firstName = value;
}
private string? _firstName;
}
使用属性有诸多好处, 例如, 您可以剔除一些不合法的数据:
public class PeopleAge {
private double age;
public double Age{
get => age;
set => age = (value >= 0 && value <= 100) ? value : throw new ArgumentOutOfRangeException();
}
}
上面这个例子就可以把明显不合理的年龄剔除.
您也可以利用属性来控制对数据的访问, 例如将数据设置为:在类外可读, 但只有在本类中可写. 或是不添加set访问器将数据设置为只读.
public class Person
{
public string? FirstName { get; private set; }
//这个属性所属的字段只有在本类中可写.
}
public class Person
{
public Person(string firstName) => FirstName = firstName;
public string FirstName { get; }//这个属性所属的字段是只读的
}