C#:类的成员--属性

属性的作用

  • 属性是对字段的扩展
  • 使用属性对外能够暴露数据
  • 使用属性对内能够保护字段、使字段不被污染
  • 属性其实是由Get/Set方法对演化而来的

为什么说属性能够保护字段?

class Program
{
    static void Main(string[] args)
    {
        Student student1 = new Student(1);
        student1.name = "xiaoming";
        student1.age = 519;
        Console.WriteLine(student1.name + "  " + student1.age);

        Student student2 = new Student(2);
        student2.name = "mike";
        student2.age = -22;
        Console.WriteLine(student2.name + " " + student2.age);

        Console.ReadKey();
    }
}

class Student
{
    public readonly int id;
    public string name;
    public int age;

    public Student(int id)
    {
        this.id = id;
    }
}

上述在只有字段的程序中,人的年龄在为负数 或者 八百岁显然是不符合实际的。这就是字段被非法数据污染的一种情况
为了解决这个问题,可以将字段设置成私有字段 然后提供公开的Get和Set方法来设置和获取字段的值

private int age;
//注意使用大驼峰命名 Get后面通常是字段的名字
public int GetAge() 
{
    return age;
}

public void SetAge(int value) 
{
    if (value>=0&&age<=120)
    {
        this.age = value;
    }
    else
    {
        throw new Exception($"{value}不在合法范围内");
    }
}
//下面是在Main方法中的调用
Student student1 = new Student(1);
student1.SetName("xiaoming");
student1.SetAge(519);
Console.WriteLine(student1.GetName() + "  " + student1.GetAge());

运行结果:
使用Get和Set方法对儿 保护字段
上面的Get和Set方法在保护字段上,十分有效Java、C++语言现在仍然在广泛地使用;C#语言的研发团队发现这种写法稍稍有些冗长,于是便发明了"属性"的概念,让开发者以属性的访问来间接达到访问字段的效果

属性的完整写法

class Program
{
    static void Main(string[] args)
    {
        Student student1 = new Student(1);
        student1.Name= "xiaoming";
        student1.Age = 19;
        Console.WriteLine(student1.Name + "  " + student1.Age);

        Student student2 = new Student(2);
        student2.Name= "mike";
        student2.Age= 22;
        Console.WriteLine(student2.Name + " " + student2.Age);


        Console.ReadKey();
    }
}

class Student
{
    public readonly int id;
    private string name;
    public string Name
    {
        get 
        {
            return name;
        }

        set 
        {
            // value在setter包装其中是一个上下文 关键字
            // value 代表给字段设置值时传入的值
            this.name = value;
        }
    }

    private int age;
    public int Age
    {
        get
        {
            return age;
        }
        set
        {
            if (value >= 0 && value <= 120)
            {
                this.age = value;
            }
            else
            {
                throw new Exception($"{value}不在合法范围内");
            }
        }
    }
    public Student(int id)
    {
        this.id = id;
    }
}

像使用字段那样使用属性 相较 Get和Set方法对儿 大大减少了程序的冗余

其实属性的getter和setter是一种语法糖---语法糖就是官方为我们隐藏一些代码,是我们使用起某些功能更加便捷的一种手段。我们可以通过C#的反编译工具来看一下属性包装器背后的秘密。

  • 按下 WIN+R 组合键 输入 ILDASM
    C#反编译工具
  • 将我们程序编译生成的 EXE文件拖入该工具中
    ILDASM反编译工具
  • 双击Name属性可以在新的窗口中看到
    属性包装器内部调用了Get和Set方法
    所以,属性包装器其实是一种语法糖。C#为我们隐藏了Get和Set方法的代码,使我们使用属性更方便。

属性声明的三种方式及快捷键

  1. 完整声明:借助VisualStuido的代码提示: propfull
    propfull
    以上我们借助代码提示快速完成了属性的完整声明;当然在Set中我们是可以写一些保护字段的逻辑的
  2. 简略声明:同样使用代码提示:prop
    prop
    • 属性的简要声明的使用场景一般使用来传递数据用的;使用简略声明这种格式不能起到保护字段的作用了。
    • 属性简略声明,我们没有声明字段,那么就可以说字段不存在么?不可以:属性的简要声明表面上看我们已经看不到字段的存在了,其实C#已经帮我们创建了字段
      简略声明的属性也会创建字段
  3. 有时我们设计好了程序后,发现只使用了字段而并没有使用属性,此时我们可以使用VS的只能重构方法CTRL+R,E组合键来重构代码。
    快速封装字段

属性能够动态地计算值 该如何理解?

class Program
{
    static void Main(string[] args)
    {
        var student = new Student() { Age = 19, Name = "baobo" };
        Console.WriteLine(student.CanWork);
        Console.ReadKey();
    }
}

class Student
{
    private string name;

    public string Name
    {
        get { return name; }
        set { name = value; }
    }

    private int age;

    public int Age
    {
        get { return age; }
        set
        {
            age = value;
        }
    }

    public bool CanWork
    {
        get
        {
            if (age >= 18)
            {
                return true;
            }
            else
            {
                return false;
            }
        }
    }
}

输出结果为:True;上述示例中CanWork属性并未显示封装一个字段,当从外界访问这个属性的时候,所得到的值是实时动态计算出来的
程序还可以改写成主动地计算值,如下

class Program
{
    static void Main(string[] args)
    {
        var student = new Student() { Age = 19, Name = "baobo" };
        Console.WriteLine(student.CanWork);
        Console.ReadKey();
    }
}

class Student
{
    private string name;

    public string Name
    {
        get { return name; }
        set { name = value; }
    }

    private int age;

    public int Age
    {
        get { return age; }
        set
        {
            age = value;
            // 每当age被赋值的时候 主动去计算 canwork字段的值
            if (age>=18)
            {
                this.canWork = true;
            }
            else
            {
                this.canWork = false;
            }
        }
    }

    private bool canWork;

    public bool CanWork
    {
        get { return canWork; }
    }
}

总之,属性是比字段要灵活很多的一种函数成员。建议在能使用属性的地方尽可能多地使用属性。以上便是对属性的总结,记录下来以便以后查阅。

原文地址:https://www.cnblogs.com/bigbosscyb/p/13702411.html