跳转到内容

C Sharp 属性基础

来自代码酷
Admin留言 | 贡献2025年4月29日 (二) 18:40的版本 (Page creation by admin bot)

(差异) ←上一版本 | 已核准修订 (差异) | 最后版本 (差异) | 下一版本→ (差异)

C#属性基础[编辑 | 编辑源代码]

介绍[编辑 | 编辑源代码]

在C#中,属性(Property)是一种特殊的类成员,它提供了一种灵活的方式来读取、写入或计算私有字段的值。属性是字段(field)的自然扩展,既保持了数据的封装性,又允许通过访问器(accessors)控制对数据的访问逻辑。

属性通常由以下部分组成:

  • 一个可选的访问修饰符(如 public, private
  • 属性类型(如 int, string
  • 属性名称
  • get 访问器(用于读取值)
  • set 访问器(用于写入值)

基本语法[编辑 | 编辑源代码]

属性的标准声明格式如下:

[access-modifier] [type] [property-name]
{
    get { /* 返回属性值 */ }
    set { /* 设置属性值 */ }
}

示例1:简单属性[编辑 | 编辑源代码]

public class Person
{
    private string _name; // 私有字段

    // Name属性
    public string Name
    {
        get { return _name; }
        set { _name = value; } // 'value'是隐式参数
    }
}

属性类型[编辑 | 编辑源代码]

1. 自动实现属性[编辑 | 编辑源代码]

C# 3.0引入的简写语法,编译器会自动生成私有字段:

public class Product
{
    public int Id { get; set; } // 自动属性
    public decimal Price { get; set; }
}

2. 只读属性[编辑 | 编辑源代码]

只有get访问器的属性:

public class Circle
{
    public double Radius { get; } = 5.0; // 初始化后不可修改
}

3. 计算属性[编辑 | 编辑源代码]

基于其他值动态计算的属性:

public class Rectangle
{
    public double Width { get; set; }
    public double Height { get; set; }
    
    public double Area 
    {
        get { return Width * Height; } // 计算得出
    }
}

访问器控制[编辑 | 编辑源代码]

可以通过访问修饰符对get/set分别控制:

public class BankAccount
{
    public decimal Balance { get; private set; } // 外部只读
    
    public void Deposit(decimal amount)
    {
        Balance += amount; // 类内部可修改
    }
}

属性 vs 字段[编辑 | 编辑源代码]

特性 属性 字段
支持 | 不支持
可分别控制get/set | 统一访问级别
可包含 | 不能包含
必须显式设置 | 有类型默认值

实际应用案例[编辑 | 编辑源代码]

数据验证示例[编辑 | 编辑源代码]

public class Student
{
    private int _age;
    
    public int Age
    {
        get => _age;
        set 
        {
            if (value < 0 || value > 120)
                throw new ArgumentOutOfRangeException("年龄必须在0-120之间");
            _age = value;
        }
    }
}

INotifyPropertyChanged 实现[编辑 | 编辑源代码]

在WPF/MVVM中的典型应用:

public class ObservableObject : INotifyPropertyChanged
{
    public event PropertyChangedEventHandler PropertyChanged;

    protected void OnPropertyChanged([CallerMemberName] string name = null)
    {
        PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(name));
    }
}

public class User : ObservableObject
{
    private string _username;
    
    public string Username
    {
        get => _username;
        set
        {
            _username = value;
            OnPropertyChanged(); // 通知UI更新
        }
    }
}

高级主题[编辑 | 编辑源代码]

索引器属性[编辑 | 编辑源代码]

允许类实例像数组一样被索引:

public class StringArray
{
    private string[] _array = new string[10];
    
    public string this[int index]
    {
        get => _array[index];
        set => _array[index] = value;
    }
}

表达式体属性[编辑 | 编辑源代码]

C# 6+支持的简写语法:

public class Point
{
    public int X { get; set; }
    public int Y { get; set; }
    
    public string Coordinates => $"({X}, {Y})"; // 表达式体属性
}

属性初始化顺序[编辑 | 编辑源代码]

graph TD A[声明字段] --> B[字段初始化] B --> C[构造函数执行] C --> D[属性设置器调用]

最佳实践[编辑 | 编辑源代码]

1. 对公有成员总是使用属性而非字段 2. 简单的get/set操作使用自动属性 3. 需要验证或计算时使用完整属性 4. 考虑对set访问器添加保护 5. 避免在属性getter中执行耗时操作

数学关系[编辑 | 编辑源代码]

属性可以看作是两个函数的组合: P(x)={fget()当读取时fset(x)当写入时

其中fgetfset分别对应get和set访问器的逻辑。