属性是一种特殊的类成员。我们使用预定义的set和get方法来访问和修改它们。属性读取和写入被转换为获取和设置方法调用。
使用字段表示法(例如object.Name)访问变量比使用自定义方法调用(例如object.GetName)更容易。然而,利用属性,我们仍然具有封装和信息隐藏的优势。换句话说,属性将数据与外部世界隔离,同时具有方便的字段访问。
接口可以有属性,但不能有字段。
属性可以是读写(它们同时具有get和set访问器)、只读(它们只有get访问器)或只写(它们只有set访问者)。
Program.cs
- var p = new Person();
- p.Name = "Jane";
-
- Console.WriteLine(p.Name);
-
- class Person
- {
- private string _name;
-
- public string Name
- {
- get { return _name; }
- set { _name = value; }
- }
- }
我们有一个具有一个属性的简单Person类。
var p = new Person(); p.Name = "Jane"; Console.WriteLine(p.Name);
我们创建Person类的一个实例。我们使用字段符号访问成员字段。
public string Name
{
...
}
我们有一个名为Name的属性。它看起来像一个常规方法声明。不同之处在于它具有称为get和set的特定访问器。
get { return _name; }
set { _name = value; }
get属性访问器用于返回属性值,set访问器用于分配新值。value关键字用于定义集合索引器分配的值。
$ dotnet run
Janes
可以创建只读属性。为了创建只读属性,我们省略了set访问器,并在实现中仅提供get访问器。
Program.cs
- var p = new Person();
- // p.Name = "Beky";
-
- Console.WriteLine(p.Name);
-
- class Person
- {
- private string _name = "Jane";
-
- public string Name
- {
- get { return _name; }
- }
- }
在示例中,我们演示了只读属性的使用。
// p.Name = "Beky";
该行现在已注释。我们不能更改属性。如果我们取消注释该行,C#编译器将发出以下错误:yProgram。cs(4,1):错误CS0200:属性或索引器的人员。无法将名称“”分配给--它是只读的。
private string _name = "Jane";
我们立即初始化该成员,因为稍后不可能。
public string Name
{
get { return _name; }
}
我们通过提供get访问器使属性只读。
C#具有自动实现或自动属性。在软件项目中,有许多简单的属性只设置或获取一些简单的值。为了简化编程并缩短代码,创建了自动属性。注意,我们不能在所有情况下使用自动属性;只有简单的。
Program.cs
- var p = new Person();
- p.Name = "Jane";
- p.Age = 17;
-
- Console.WriteLine($"{p.Name} is {p.Age} years old");
-
- class Person
- {
- public string Name { get; set; }
- public int Age { get; set; }
- }
这个代码要短得多。我们有一个Person类,其中有两个属性:Name和Age。
var p = new Person();
p.Name = "Jane";
p.Age = 17;
Console.WriteLine($"{p.Name} is {p.Age} years old");
我们通常像往常一样使用这些属性。
public string Name { get; set; }
public int Age { get; set; }
这里我们有两个自动属性。没有访问器的实现,也没有成员字段。编译器将为我们完成剩下的工作。
$ dotnet run Jane is 17 years old
自C#7.0以来,属性可以通过表达式体定义简化。表达式体定义由=>符号和要分配给属性或从属性检索的表达式组成。
Program.cs
- var u = new User("John Doe", "gardener");
-
- Console.WriteLine($"{u.Name} is a {u.Occupation}");
-
- class User
- {
- string name;
- string occupation;
-
- public User(string name, string occupation)
- {
- this.name = name;
- this.occupation = occupation;
- }
-
- public string Name
- {
- get => name;
- set => name = value;
- }
-
- public string Occupation
- {
- get => occupation;
- set => occupation = value;
- }
- }
在本例中,我们使用表达式体定义来定义用户类的属性。
$ dotnet run
John Doe is a gardenerl
我们可以使用访问修饰符标记属性,如public、private或protected。属性也可以是静态的、抽象的、虚拟的和密封的。它们的用法与常规方法相同。
Program.cs
- var bs = new Base();
- var dr = new Derived();
-
- Console.WriteLine(bs.Name);
- Console.WriteLine(dr.Name);
-
- class Base
- {
- protected string _name = "Base class";
-
- public virtual string Name
- {
- set { _name = value; }
- get { return _name; }
- }
- }
-
- class Derived : Base
- {
- protected new string _name = "Derived class";
-
- public override string Name
- {
- set { _name = value; }
- get { return _name; }
- }
- }
在前面的示例中,我们定义了一个虚拟属性,并在派生类中重写它。
public virtual string Name
{
set { _name = value; }
get { return _name; }
}
名称属性用虚拟关键字标记。
protected new string _name = "Derived class";
我们在派生类中隐藏了一个成员。为了抑制编译器警告,我们使用new关键字。
public override string Name
{
set { _name = value; }
get { return _name; }
}
这里我们重写基类的Name属性。