• C#学习 - 字段、属性、索引器、常量


    字段、属性、索引器、常量都是用来表达数据的
    C#的类和结构体可能会有如下成员:常量、字段、方法、属性、索引器、事件、运算符、构造函数、析构函数、类型

    字段(field)

    字段是一种表示与对象或类型(类与结构体)相关联的变量,字段是类型的成员
    字段是为一个对象或类型存储数据,字段的值可以表现这个对象或类型当前的状态。字段旧称是“成员变量”

    • 与对象关联的字段称为“实例对象”
    internal class Program
    {
        static void Main(string[] args)
        {
            People p1 = new People();
            p1.Age = 20;
        }
    }
    class People
    {
        public int Age;//实例字段
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 与类型关联的字段称为“静态字段”,由static修饰
    internal class Program
    {
        static void Main(string[] args)
        {
            People p1 = new People();
            p1.Age = 20;
            People.PeoNum();
        }
    }
    class People
    {
        public int Age;
        public static int Num;//静态字段,记录人数
        public People()
        {
            People.Num++;
        }
        public static void PeoNum()
        {
            Console.WriteLine(People.Num);
        }
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22

    注:字段的名字一定是一个名词

    声明字段

    字段的声明要在类型里面
    特性(可删除) + 修饰符组合(需要有意义,可删除) + 字段的数据类型 + 变量声明器(可删除) + “;”
    字段声明不是一个语句,语句只出现在函数体中,而字段是出现在类型中
    字段的默认值就是字段数据类型的默认初始值
    字段也可以在构造器中初始化值
    实例类型每次都会初始化,静态类型只有在第一次调用时会初始化

    • 实例字段初始化是对象被创建时
    • 静态字段初始化是类型被加载时

    只读字段

    修饰符中有一个“readonly”(只读),在声明时初始化后无法赋值,静态只读字段可在静态构造器中初始化

    internal class Program
    {
        static void Main(string[] args)
        {
            Console.WriteLine(Brush.DefaultColor.Red);
            Console.WriteLine(Brush.DefaultSize);
        }
    }
    struct Color
    {
        public int Red;
        public int Green;
        public int Blue;
    }
    class Brush
    {
        public static readonly Color DefaultColor = new Color() { Blue = 0, Green = 0, Red = 0 };
        public static readonly int DefaultSize;
        static Brush()//静态构造器
        {
            Brush.DefaultSize = 5;
        }
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23

    属性(property)

    用于访问对象或类型的特征的成员,特征反映了状态
    属性是字段的自然拓展

    • 字段更偏向于实例对象在内存中的布局;属性更偏向于反映现实世界对象的特征
    • 数据存储在字段中时,数据的状态由字段中存储的值而定;属性可以实时动态地计算出数据的特征
    • 字段存储的值可能是错误的(被非法值污染),而属性可以通过一些逻辑保护字段不被非法值污染
    • 建议永远使用属性来向外暴露数据,字段永远用 private 或 protected 修饰
      属性是由Get/Set方法进化而来
    internal class Program
    {
        static void Main(string[] args)
        {
            People p1 = new People();
            p1.Age = 1000;//对于人的年龄来说,1000就是个非法值
            //而字段就可能被非法值污染
        }
    }
    class People
    {
        public int Age;
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13

    Get/Set方法:

    internal class Program
    {
        static void Main(string[] args)
        {
            try
            {
                People p1 = new People();
                p1.SetAge(20);
                People p2 = new People();
                p2.SetAge(250);//250是非法值
                int avgAge = (p1.GetAge() + p2.GetAge()) / 2;
                Console.WriteLine(avgAge);
            }
            catch (Exception ex)
            {
                Console.WriteLine(ex.Message);
            }
        }
    }
    class People
    {
        private int age;//字段变成private时,使用驼峰法命名
        //使用一对方法保护这个字段。一个方法用来获取这个字段的值;一个为这个字段设置值
        public int GetAge()//获取值
        {
            return age;
        }
        public void SetAge(int value)//设置值
        {
            if (value >= 0 && value <= 120)
            {
                age = value;
            }
            else
            {
                throw new Exception("Age value has error.");
            }
        }
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39

    属性:

    internal class Program
    {
        static void Main(string[] args)
        {
            try
            {
                People p1 = new People();
                p1.Age = 20;
                People p2 = new People();
                p2.Age = 25;
                int avgAge = (p1.Age + p2.Age) / 2;
                Console.WriteLine(avgAge);
            }
            catch (Exception error)
            {
                Console.WriteLine(error.Message);
            }
        }
    }
    class People
    {
        private int age;
        public int Age//Age属性
        {
            //括号内为访问器
            get//获取值
            {
                return age;
            }
            set//设置值
            {
                if(value >=0&&value<=120)//C#中准备了一个默认的变量value
                {//value是上下文关键字,在某个特定的代码上下文中其是关键字
                    age = value;
                }
                else
                {
                    throw new Exception("Age value has error.");
                }
            }
        }
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41
    • 42

    属性是一种“语法糖”,上段代码中的get和set会自动调用get_Age()和set_Age(int32)

    属性的声明

    注:属性名字需要是名词或名词短语
    属性有完整声明和简略声明,区别主要是 get 和 set 的使用

    • 完整的声明
      特性(可删除) + 修饰符组合(需要有意义,可删除) + 属性的数据类型 + 属性的名字 + { get 和 set }
    private int myVar;
    public int MyProperty
    {
        get { return myVar; }
        set { myVar = value; }
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6

    如果一个属性只有 get 没有 set 则是只读属性;而如果一个属性只有 set 没有 get 则是只写属性
    VS中输入propfull+敲击两下tab就能自动出现完整的声明
    使用静态属性时,对应保护的字段也需要被static修饰

    • 简略的声明
      简略的属性声明与字段类似,不受保护,可能会被非法值污染
    public int MyProperty { get; set; }
    
    • 1

    VS中输入prop+敲击两下tab就能自动出现完整的声明
    简略声明会在后台封装一个私有变量

    • 重构声明
      输入一个私有字段,光标置于字段上,Ctrl+R -> Ctrl+E

    只读属性

    只读属性只有get,没有set

    private int myVar;
    public int MyProperty
    {
        get { return myVar; }
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5

    还有一类特殊的“只读”属性,是外界无法访问 set 方法,只能在内部使用 set

    private int myVar;
    public int MyProperty
    {
        get { return myVar; }
        private set { myVar = value; }
    }
    public void MethodSet()
    {
    	MyProperty = 10;
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10

    动态计算值

    internal class Program
    {
        static void Main(string[] args)
        {
            People p1 = new People();
            p1.Age = 15;
            Console.WriteLine(p1.CanWork);
        }
    }
    class People
    {
        private int age;
    
        public int Age
        {
            get { return age; }
            set { age = value; }
        }
        public bool CanWork
        { //这里的 CanWork 就是动态计算的属性
            get
            {
                if (age >= 16)
                {
                    return true;
                }
                else
                {
                    return false;
                }
            }
        }
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33

    索引器(indexer)

    索引器能使对象能够用以数组相同的方法进行索引(即是使用下标)
    一般有索引器这个成员的类是集合类型
    VS中输入indexer+敲击两下tab就能自动出现索引器
    索引器应用于非集合类型:

    internal class Program
    {
        static void Main(string[] args)
        {
            WorkWages wages = new WorkWages();
            wages["Teacher"] = 3000;//为教师工作工资赋值
            var TeacherWages = wages["Teacher"];//获取工资值
            Console.WriteLine(TeacherWages);
        }
    }
    class WorkWages//用来检测不同工作工资
    {                      //键 -- 值
        private Dictionary<string, int> wagesDictinoary = new Dictionary<string, int>();
        public int? this[string work]//索引器
        {
            get 
            {   //若输入的工作存在,则返回工资
                if (wagesDictinoary.ContainsKey(work))
                {
                    return wagesDictinoary[work];
                }
                else
                {   //若输入的工作不存在,则返回NULL
                    return null;
                }
            }
            set 
            {   //判断用户设定的工资值是否为NULL
                if (value.HasValue == false)
                {   //若为NULL,则报错
                    throw new Exception("Wages is null.");
                }
                if (wagesDictinoary.ContainsKey(work))
                {
                    wagesDictinoary[work] = value.Value;//value为可空类型
                }                       //可空类型.Value则是这个类型真正的值
                else
                {   //若字典中不存在这个工作,则在字典中加入一条“键和值”
                    wagesDictinoary.Add(work, value.Value);
                }
            }
        }
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41
    • 42
    • 43

    常量(constant)

    用来表示常量值的类成员,使用常量可以提高程序运行效率
    比如Math.PI就是个常量,使用时会用一个常量代替这个标识符
    常量需要用 const 修饰
    常量隶属于类型而不是对象,即没有“实例常量”,“实例常量”可以用只读字段来代替

    • 成员常量:类的成员中的常量
    • 局部常量:在声明变量时,在前面用 const 修饰
    internal class Program
    {
        static void Main(string[] args)
        {
            Console.WriteLine(NASA.WebURL);//调用成员常量需要使用类型 + . + 常量名称
        }
    }
    class NASA
    {
        public const string WebURL = "https://www.nasa.gov/";
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11

    各种“只读”作用

    • 常量:提高程序可读性和执行效率
    • 只读字段:防止对象的值被改变
    • 只读属性(静态或非静态):向外暴露不允许修改的数据
    • 静态只读字段:让成为常量的值其类型不能被常量声明接受。比如常量不能接收结构体类型,此时就只能用静态只读字段
  • 相关阅读:
    Android多模块打包aar
    windows上 adb devices有设备 wsl上没有
    H7-TOOL的I2C接口方式脱机烧录操作方法,已经发布(2022-07-16)
    【毕业设计】 基于Django的会议室预定系统
    格雷码与普通二进制码的相互转换——学习笔记
    C陷阱与缺陷 第8章 建议与答案 8.2 答案
    Docker从入门到进阶之进阶操作(5) —— 实战演练【nginx负载均衡-轮询】
    Python跳盆算法,来自物质结构的优化算法
    安全可信 | 首批 天翼云通过可信云安全云工作负载保护平台评估
    CANAPE中加载DBC后,如何在脚本中获取到DBC内的信号量
  • 原文地址:https://blog.csdn.net/Pokipata/article/details/133838483