属性的作用
- 属性是对字段的扩展
- 使用属性对外能够暴露数据
- 使用属性对内能够保护字段、使字段不被污染
- 属性其实是由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方法在保护字段上,十分有效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
- 将我们程序编译生成的 EXE文件拖入该工具中
- 双击Name属性可以在新的窗口中看到
所以,属性包装器其实是一种语法糖。C#为我们隐藏了Get和Set方法的代码,使我们使用属性更方便。
属性声明的三种方式及快捷键
- 完整声明:借助VisualStuido的代码提示: propfull
以上我们借助代码提示快速完成了属性的完整声明;当然在Set中我们是可以写一些保护字段的逻辑的 - 简略声明:同样使用代码提示:prop
- 属性的简要声明的使用场景一般使用来传递数据用的;使用简略声明这种格式不能起到保护字段的作用了。
- 属性简略声明,我们没有声明字段,那么就可以说字段不存在么?不可以:属性的简要声明表面上看我们已经看不到字段的存在了,其实C#已经帮我们创建了字段
- 有时我们设计好了程序后,发现只使用了字段而并没有使用属性,此时我们可以使用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; }
}
}
总之,属性是比字段要灵活很多的一种函数成员。建议在能使用属性的地方尽可能多地使用属性。以上便是对属性的总结,记录下来以便以后查阅。