C#属性教程展示了如何在C#中使用属性。
属性是一个成员,它提供了一种灵活的机制来读取、写入或计算私有字段的值。
属性使用访问器,通过访问器可以读取、写入或操作私有字段的值。属性读取和写入被转换为get和set方法调用。属性保护数据不受外界影响,同时具有方便的现场访问。
get属性访问器用于返回属性值,set属性访问器用于分配新值。init属性访问器仅在对象构造期间用于分配新值。value关键字用于定义由set或init访问器分配的值。
属性可以是读写的(它们同时具有get和set访问器)、只读的(它们只有get访问器)或只写的(它们只有setaccessor)。
带有支持字段的C#属性
以下示例使用带有支持字段的属性。
var u = new User();
u.Name = "Jane";
Console.WriteLine(u.Name);
class User
{
private string _name;
public string Name
{
get { return _name; }
set { _name = value; }
}
}
我们有Name属性和_namebackingfield。
var u = new User();
u.Name = "Jane";
Console.WriteLine(u.Name);
我们创建了一个User类的实例。我们使用字段表示法访问成员字段。
public string Name
{
...
}
我们有一个名为Name的属性。它看起来像一个常规方法声明。不同之处在于它有特定的访问器,称为get和set。
get { return _name; }
set { _name = value; }
get属性访问器用于返回属性值,set访问器用于分配新值。value关键字用于定义由setaccessor分配的值。
C#只读属性
为了创建只读属性,我们在实现中省略了set访问器并仅提供了get访问器。
var u = new User("John Doe", "gardener");
Console.WriteLine(u);
class User
{
private string _name;
private string _occupation;
public User(string name, string occupation)
{
_name = name;
_occupation = occupation;
}
public string Name
{
get { return _name; }
}
public string Occupation
{
get { return _occupation; }
}
public override string ToString()
{
return $"{_name} is a {_occupation}";
}
}
在示例中,我们有只读属性。一旦在构造函数中初始化,它们就不能被修改。
public string Name
{
get { return _name; }
}
我们通过提供一个get访问器将属性设置为只读。
C#自动实现的属性
C#具有自动实现或自动属性。借助自动属性,编译器可以透明地为我们提供支持字段。
var u = new User();
u.Name = "John Doe";
u.Occupation = "gardener";
Console.WriteLine($"{u.Name} is a {u.Occupation}");
class User
{
public string Name { get; set; }
public string Occupation { get; set; }
}
这段代码要短得多。我们有一个User类,其中有两个属性:Name和Occupation。
var u = new User();
u.Name = "John Doe";
u.Occupation = "gardener";
Console.WriteLine($"{u.Name} is a {u.Occupation}");
我们通常像往常一样使用这些属性。
public string Name { get; set; }
public string Occupation { get; set; }
这里我们有两个自动属性。没有访问器的实现,也没有成员字段。编译器会为我们完成剩下的工作。
$ dotnet run John Doe is a gardener
C#初始化属性
init关键字用于创建仅初始化属性;这些属性只能在对象构造期间初始化。
var u = new User("John Doe", "gardener");
Console.WriteLine(u);
class User
{
public User(string name, string occupation)
{
Name = name;
Occupation = occupation;
}
public string Name { get; init; }
public string Occupation { get; init; }
public override string ToString()
{
return $"{Name} is a {Occupation}";
}
}
我们定义了两个init-only属性;它们在构造函数中初始化。之后,它们变得不可变。
public string Name { get; init; }
public string Occupation { get; init; }
init-only属性是使用init关键字创建的。
C#表达式主体定义
可以使用表达式主体定义来简化属性。表达式主体定义由=>符号和后跟要分配给属性或从属性检索的表达式组成。
var u = new User("John Doe", "gardener");
Console.WriteLine($"{u.Name} is a {u.Occupation}");
class User
{
private string _name;
private string _occupation;
public User(string name, string occupation)
{
Name = name;
Occupation = occupation;
}
public string Name
{
get => _name;
set => _name = value;
}
public string Occupation
{
get => _occupation;
set => _occupation = value;
}
}
在示例中,我们使用表达式主体定义来定义User类的属性。
$ dotnet run John Doe is a gardener
其他说明
我们可以使用访问修饰符标记属性,例如public、private或protected。属性也可以是static、abstract、virtual和sealed。它们的用法与常规方法相同。
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; }
}
}
在前面的示例中,我们定义了一个虚拟属性并在Derived类中覆盖它。
public virtual string Name
{
set { _name = value; }
get { return _name; }
}
Name属性用virtual关键字标记。
protected new string _name = "Derived class";
我们在派生类中隐藏了一个成员。为了抑制编译器警告,我们使用new关键字。
public override string Name
{
set { _name = value; }
get { return _name; }
}
在这里我们覆盖了Base类的Name属性。
在本文中,我们介绍了C#属性。
列出所有C#教程。
