C#语言入门详解 第十七讲 (字段、属性、索引器、常量)
创始人
2024-03-23 03:57:51
0

C#语言入门详解 第十七讲 (字段、属性、索引器、常量)

在C#语言中,类(或结构体)包含以下成员:
在这里插入图片描述

什么是字段

  • 字段(field)是一种表示与对象或类型(类与结构体)关联的变量
    字段是用来储存数据的,多个字段就可以描述对象的状态
  • 字段是类型的成员,旧称“成员变量”
  • 与对象关联的字段亦称“实例字段”
  • 与类型关联的字段称为“静态字段”,有static修饰
    internal class Program{static void Main(string[] args){// 实例化一个对象Student stu1 = new Student();stu1.Age = 40;stu1.Score = 90;Student stu2 = new Student();stu2.Age = 24;stu2.Score = 60;Student.ReportAmount();  // >>>2}}class Student{// 定义实例字段(只有通过实例化之后才能被调用,不能通过类名调用)public int Age;public int Score;// 定义静态字段(通过类名调用,不能通过实例调用)public static int AverageAge;public static int AverageScore;public static int Amount;public Student(){Student.Amount++;}public static void ReportAmount(){Console.WriteLine(Student.Amount);}}
    internal class Program{static void Main(string[] args){List students = new List();for (int i = 0; i < 100; i++){Student student = new Student();student.Age = 24;student.Score = i;students.Add(student);}int totalAge = 0;int totalScore = 0;foreach (Student student in students){totalAge += student.Age;totalScore += student.Score;}Student.AverageAge = totalAge / Student.Amount;Student.AverageScore = totalScore / Student.Amount;Student.ReportAmount();  // >>>100Student.ReportAverageAge();  // >>>24Student.ReportAverageScore();  // >>>49}}class Student{// 定义实例字段(只有通过实例化之后才能被调用,不能通过类名调用)public int Age;public int Score;// 定义静态字段(通过类名调用,不能通过实例调用)public static int AverageAge;public static int AverageScore;public static int Amount;public Student(){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#语言定义文档
    字段必须包含在类型(类和和结构体)中,不能直接写在命名空间内,不能写在方法内(局部变量)
    字段声明最常用的两种形式
    只读字段的作用:用于保存一旦实例化后就不希望被修改的数据
public int Age; // 访问级别 变量类型 变量名;
public static int Amount; // 访问级别 static 变量类型 变量名;
// 建议在声明字段时就进行初始化
// 只读实例字段readonly
internal class Program{static void Main(string[] args){Student student = new Student(1);Console.WriteLine(student.ID); // >>>1student.ID = 2; // >>>无法编译,不能修改只读字段}}class Student{// 定义实例字段(只有通过实例化之后才能被调用,不能通过类名调用)public readonly int ID;  // 只读实例字段public int Age;public int Score;// 定义静态字段(通过类名调用,不能通过实例调用)public static int AverageAge;public static int AverageScore;public static int Amount;public Student(int ID)  // 动态初始化器,每次实例化都会执行{this.ID = ID;  // 初始化只读字段}}
// 静态只读字段
internal class Program
{static void Main(string[] args){Console.WriteLine(Brush.DefaultColor.Red);  // >>>0Console.WriteLine(Brush.DefaultColor.Green);  // >>>0Console.WriteLine(Brush.DefaultColor.Blue);  // >>>0}
}
struct Color
{public int Red;public int Green;public int Blue;
}class Brush
{public static readonly Color DefaultColor = new Color() { Red = 0, Green = 0, Blue = 0 };// 上面的语句和下面的作用是一致的public static readonly Color DefaultColor;static Brush(){Brush.DefaultColor = new Color() { Red = 0, Green = 0, Blue = 0 };}
}
  • 尽管字段声明带有分号,但不是语句
  • 字段的名字一定有名词

字段的初始值

  • 无显式初始值时,字段获得其类型的默认值,所以字段“永远都不会未被初始化”
  • 实例字段初始化的时机——对象创建时(每次创建实例都会执行一次)
  • 静态字段初始化的时机——类型被加载时(只执行一次)
  • 类的初始化也有静态初始化和动态初始化
    class Student{// 定义实例字段(只有通过实例化之后才能被调用,不能通过类名调用)public int Age;public int Score;// 定义静态字段(通过类名调用,不能通过实例调用)public static int AverageAge;public static int AverageScore;public static int Amount;public Student()  // 动态初始化器,每次实例化都会执行{}static Student()  // 静态初始化器,只在类加载时被执行{}}

只读字段

  • 实例只读字段
  • 静态只读字段

什么是属性

  • 属性(property)是一种用于访问对象或类型的特征的成员,特征反映了状态
  • 属性是字段的自然扩展
// 字段怎样向属性进化的??
// 将字段的访问级别由public改为private
// 变量名使用小写字母age
// 定义GetAge()和SetAge()方法,分别获取和设置属性值
internal class Program{static void Main(string[] args){try{Student stu1 = new Student();Student stu2 = new Student();Student stu3 = new Student();stu1.SetAge(20);stu2.SetAge(20);stu3.SetAge(200);double AverageAge = (stu1.GetAge() + stu2.GetAge() + stu3.GetAge()) / 3;Console.WriteLine(AverageAge);}catch (Exception ex){Console.WriteLine(ex.Message);}}}class Student{private int age;public int GetAge(){ return this.age; }public void SetAge(int age){if (age > 0 & age < 100){this.age = age;}else{throw new Exception("Age value has error!!");}}}
// 在C#中属性怎么创建??
// 定义名为Age的public变量
// 在变量名后加入{get{} set{}}
internal class Program{static void Main(string[] args){try{Student stu1 = new Student();Student stu2 = new Student();Student stu3 = new Student();stu1.Age = 20;stu2.Age = 20;stu3.Age = 20;double AverageAge = (stu1.Age + stu2.Age + stu3.Age) / 3;Console.WriteLine(AverageAge);}catch (Exception ex){Console.WriteLine(ex.Message);}}}class Student{public int Age{get{return this.Age;}set{if (value > 0 & value < 100) // value是上下文关键字,在使用set时,value代指用户输入的指{this.Age = value;}else{throw new Exception("Age value has error!!");}}}}
    • 从命名上看,字段(field)更偏向于实例对象在内存中的布局,属性(property)更偏向于反映现实世界对象的特征
    • 对外:暴露数据,数据可以是存储在字段里的,也可以是动态计算出来的
    • 对内:保护字段不被非法值“污染”
  • 属性由Get/Set方法对进化而来
  • 又一个==“语法糖”==——属性背后的秘密

属性的声明

  • 完整声明——后台(back)成员变量与访问器(注意使用code snippet和refactor工具)
    • 在vs中完整声明的快捷方法,在VS中输入“propfull”并按两下tab键,会自动弹出下面代码,并可以通过tab键继续修改
private int myVar;
public int MyProperty
{get { return myVar; }set { myVar = value; }
}
  • 简略声明——只有访问器(查看IL代码)
    • 在vs中完整声明的简略声明,在VS中输入“prop”并按两下tab键,会自动弹出下面代码,并可以通过tab键继续修改
public int MyProperty { get; set; }
  • 动态计算值的属性
  • 注意实例属性的静态属性
  • 属性的名字一定是名词
  • 只读属性——只用getter没有setter
    • 尽管语法上正确,几乎没有人使用“只写属性”,因为属性的主要目的是通过向外暴露数据而表示对象/类型的状态

属性与字段的关系

  • 一般情况下,他们都用于实体的状态
  • 属性大多数情况下是字段的包装器
  • 建议:永远使用属性(而不是字段)来暴露数据,即字段永远都是private或protected的

什么是索引器

  • 索引器(indexer)是这样一种成员:它使对象能够用与数组相同的方式(即使用下标)进行索引
internal class Program{static void Main(string[] args){Student student = new Student();var mathScore = student["Math"];Console.WriteLine(mathScore==null); // >>>turestudent["Math"] = 90;var newMathScore = student["Math"];Console.WriteLine(newMathScore); // >>>90}}class Student{// 声明一个名为scoreDictionary的字典private Dictionary scoreDictionary = new Dictionary();// 创建索引器,快捷方式indexer+两下tab// int?表示可以是空值public int? this[string subject]{get { /* return the specified index here */ if (this.scoreDictionary.ContainsKey(subject)){return scoreDictionary[subject];}else{return null;}}set { /* set the specified index to value here */if (value.HasValue == false){throw new Exception("Score cannot be null");}if (this.scoreDictionary.ContainsKey(subject)){scoreDictionary[subject] = value.Value;}else{this.scoreDictionary.Add(subject, value.Value);}}}}

索引器的声明

  • 参见C#语言定义文档
  • 注意:没有静态索引器

什么是常量

  • 常量(constant)是表示常量值(即,可以在编译时计算的值)的类成员
  • 常量隶属于类型而不是对象,即没有“实例常量”
    • “实例常量”的角色由只读实例字段来担当

常量的声明

public const double PI;

各种“只读”的应用场景

  • 为了提高程序的可读性和执行效率——常量
  • 为了防止对象的值被改变——只读字段
  • 向外暴露不允许修改的数据——只读属性(静态或非静态),功能与常量有一些重叠
  • 当希望成为常量的值其类型不能被常量声明接受时(类/自定义结构体)——静态只读字段

相关内容

热门资讯

原创 吉... 12月26日,欣旺达公告自家子公司欣旺达动力被吉利旗下的威睿电动汽车告了,索赔金额高达23.14亿元...
无惧苹果起诉,爆料人再发iPh... IT之家 12 月 27 日消息,据科技媒体 Phone Arena 昨天报道,在今年 7 月被苹果...
因电芯质量问题索赔23.14亿... 齐鲁晚报·齐鲁壹点 郭辰昊 12月26日,欣旺达发布公告称,子公司欣旺达动力于2025年12月25日...
民族团结进步促进法草案等重要法... 原标题:三部重要法律案将提请2026年全国人代会审议 十四届全国人大常委会第十九次会议12月27日表...
改革开放再深化,激活制度创新“... 改革开放再深化,激活制度创新“关键一招” ——聚焦省委经济工作会议④ 刚刚结束的省委经济工作会议提出...
“理论+百姓+文艺” 北京城市... “从城市绿心的生态蝶变到社区服务的温度升级,党的二十届四中全会精神正悄然融入城市副中心市民的日常生活...
咖啡因风波中的霸王茶姬,“将对... 因为产品咖啡因含量问题,现制茶饮品牌霸王茶姬(NASDAQ.CHA)再次登上热搜。 12月26日,霸...
丰田UA80八速变速箱存设计缺... 据汽车媒体CarScoops,丰田近期遭遇两起集体诉讼,核心指控其广泛使用的UA80八速自动变速箱存...
搭建温暖桥梁:湖南芙蓉律师事务... 这个冬天,湖南芙蓉律师事务所想搭一座“温暖桥梁”——发起“橙”意满满助农公益捐赠活动,计划捐赠20万...