什么是字段
字段(field)是一种表示与对象或类型(类与结构体)关联的变量
字段是类型的成员,旧称“成员变量”
与对象关联的字段亦称“实例字段”
与类型关联的字段称为“静态字段”,由static修饰
namespace Field{ class Program { static void Main(string[] args) { List<Student> stulist = new List<Student>(); for (int i = 0; i < 100; i ) { Student stu = new Student(); stu.Age = 24; stu.Score = i; stulist.Add(stu); } int totalAge = 0; int totalScore = 0; foreach (var stu in stulist) { totalAge = stu.Age; totalScore = stu.Score; } Student.AverageAge = totalAge / Student.Amount; Student.AverageScore = totalScore / Student.Amount; Student.ReportAmount(); Student.ReportAverageAge(); Student.ReportAverageScore(); } } class Student { public int Age; public int Score; public static int AverageAge; public static int AverageScore; public static int Amount; public Student() { Amount ; } public static void ReportAmount() { Console.WriteLine(Student.Amount); } public static void ReportAverageAge() { Console.WriteLine(Student.AverageAge); } public static void ReportAverageScore() { Console.WriteLine(Student.AverageScore); } }}
字段的声明
参见C#语言定义文档
尽管字段声明带有分号,但它不是语句
字段的名字一定是名词
字段的初始值
无显式初始化时,字段获得其类型的默认值,所以字段“永远都不会未被初始化”
实例字段初始化的时机——对象创建时
静态字段初始化的时机——类型被加载时
只读字段
实例只读字段
namespace Field{ class Program { static void Main(string[] args) { Student stu = new Student(1); Console.WriteLine(stu.ID); stu.ID = 2;//(无法通过编译)只读字段无法通过赋值修改 } } class Student { public readonly int ID; public Student(int id) { this.ID = id;//只读字段只能在构造器中修改默认值 } } }
静态只读字段
namespace Field{ class Program { static void Main(string[] args) { Console.WriteLine(Brush.defaultColor.Red); Console.WriteLine(Brush.defaultColor.Green); Console.WriteLine(Brush.defaultColor.Blue); Brush.defaultColor = new Color() { Red = 255, Green = 255, Blue = 255 };//(无法通过编译)静态只读字段同样也不能赋值修改 } } struct Color { public int Red; public int Green; public int Blue; } class Brush { public static readonly Color defaultColor; static Brush() { Brush.defaultColor = new Color() { Red = 0, Green = 0, Blue = 0 }; } } }
什么是属性
从命名上看,字段(field)更偏向于实例对象再内存中的布局,属性(property)更偏向于反映现实世界对象的特征
对外:暴露数据,数据可以是存储在字段里的,也可以是动态计算出来的
对内:保护字段不被非法值“污染”
属性(Property)是一种用于访问对象或类型的特征的成员,特征反映了状态
属性是字段的自然扩展
属性由Get/Set方法对进化而来
namespace Property{ class Program { static void Main(string[] args) { try { Student stu1 = new Student(); stu1.Age = 20; //stu1.SetAge(10); Student stu2 = new Student(); stu2.Age = 20; //stu2.SetAge(10); Student stu3 = new Student(); stu3.Age = 20; //stu3.SetAge(10); int avgAge = (stu1.Age stu2.Age stu3.Age) / 3; //int avg = (stu1.GetAge() stu2.GetAge() stu3.GetAge()); C中的Get() set()方法对 Console.WriteLine(avgAge); } catch (Exception ex) { Console.WriteLine(ex.Message); } } } class Student { private int age; public int Age//声明了一个Age属性 { get { return this.age; } set { if (value>=0&&value<=120) { this.age = value; } else { throw new Exception("Age has Error"); } } } public int GetAge() { return this.age; } public void SetAge(int value) { if (value >= 0 && value <= 120) { this.age = value; } else { throw new Exception("Age has Error"); } } }}
又一个“语法糖”——属性背后的秘密
属性的声明
完整声明(快捷键propfull双击tab)——后台(back)成员变量与访问器
namespace Property{ class Program { static void Main(string[] args) { try { Student stu = new Student(); stu.Age = 20; Student.Amount = 100; } catch (Exception ex) { Console.WriteLine(ex.Message); } } } class Student { private int age; public int Age//实例属性 { get { return age; } set { if (value >= 0 && value <= 120) { age = value; } else { throw new Exception("Age value has error"); } } } private static int amount; public static int Amount//静态属性 { get { return amount; } set { if (value > 0) { amount = value; } else { throw new Exception("Amount value has error"); } } } } }
简略声明(快捷键prop双击tab)——只有访问器(查看IL代码)
namespace Property{ class Program { static void Main(string[] args) { Student stu = new Student(); stu.Age = 1; } } class Student { public int Age { get; set; } } }
动态计算值的属性
namespace Property{ class Program { static void Main(string[] args) { Student stu = new Student(); stu.Age = 18; Console.WriteLine(stu.canWork); } } class Student { private int age; public int Age { get { return age; } set { age = value; } } public bool canWork //只读属性 { get { if (this.age > 16) { return true; } else { return false; } } } } }
另一种写法:
namespace Property{ class Program { static void Main(string[] args) { } } class Student { private int age; public int Age { get { return age; } set { age = value; this.CalculateCanWork(); } } private bool canWork; public bool CanWork { get { return canWork; } } private void CalculateCanWork() { if (this.age>=16) { this.canWork = true; } else { this.canWork = false; } } } }
注意实例属性和静态属性
属性的名字——定是名词
只读属性——只有Getter,没有Setter。(尽管语法上正确,几乎没有人使用“只写属性”,因为属性的主要目的是通过向外暴露数据而表示对象/类型的状态)
属性与字段的关系
一般情况下,它们都用于表示实体(对象或类型)的状态
属性大多数情况下是字段的包装器(warpper)
建议:永远使用属性(而不是字段)来暴露数据,即字段永远都是private或propected的
什么是索引器
索引器(indexer)是这样一种成员:它使对象能够用与数组相同的方式(即使用下标)进行索引
索引器的声明(键入indexer双击tab)
参见C#语言定义文档
注意:没有静态索引器
namespace Property{ class Program { static void Main(string[] args) { Student stu = new Student(); stu["math"] = 90; var mathScore = stu["math"]; Console.WriteLine(mathScore); } } class Student { private Dictionary<string, int> scoreDictionary = new Dictionary<string, int>(); public int? this[string subject]//声明索引器 { get { if (this.scoreDictionary.ContainsKey(subject)) { return this.scoreDictionary[subject]; } else { return null; } } set { if (value.HasValue == false) { throw new Exception("Score value has error"); } if (this.scoreDictionary.ContainsKey(subject)) { this.scoreDictionary[subject] = value.Value; } else { this.scoreDictionary.Add(subject, value.Value); } } } } }
什么是常量
常量(constant)是表示常量值(即,可以在编译时计算的值)的类成员
常量隶属于类型而不是对象,即没有“实例常量”。(“实例常量”的角色由只读实例字段来担当)
注意区分成员常量与局部常量
常量的声明
namespace Property{ class Program { static void Main(string[] args) { Console.WriteLine(Web.website); } } class Web { public const string website = "http://www.bilibili.com";//声明常量 }}
各种“只读”的应用场景
为了提高程序可读性和执行效率——常量
为了防止对象的值被修改——只读字段
向外暴露不允许修改的数据——只读属性(静态或非静态),功能与常量有一些重叠
当希望成为常量的值其类型不能被常量声明接受时(类/自定义结构体)——静态只读字段
联系客服