八、字段、属性、索引器和常量

八、字段、属性、索引器和常量

类的成员有以下这些:

在这里插入图片描述

字段

在这里插入图片描述

实例字段,用来表示对象实例的状态。

静态字段,用来表示整个类型的状态。

声明字段的时候对字段初始化和,在构造器中初始化字段,这两个是等价的。

namespace DataMemberExample {
    internal class Program {
        static void Main(string[] args) {
            Student stu1 =  new Student();
            stu1.Age = 20;
            stu1.Score = 90;

            Student.ReportAmount();
            int y = Student.X;
        }
    }
    class Student {
        public int Age;
        public int Score;
        public const int X = 2;

        public static int Amount;

        public Student()
        {
            Amount++;
        }

        public static void ReportAmount() {
            Console.WriteLine(Student.Amount);
        }
    }
}

除了实例构造器以外,还有静态构造器
静态构造器,在类被加载的时候就会调用,并且只会调用一次
,和静态字段一样。

在这里插入图片描述

//除了实例构造器以外,还有静态构造器
//静态构造器,在类被加载的时候就会调用,并且只会调用一次
static Student() {

}

只读字段,既可以在声明的时候初始化,又可以在构造器中初始化。

属性

在这里插入图片描述

C#中的属性,实际上就是Java中的gettersetter方法演变过来的,都是为了避免字段直接被外界访问到。

而C#的属性,在Java的基础上还改变了一点。对gettersetter方法还进行了封装。

最初人们用来保护字段的方法,在C++和Java中使用的就是这个办法。

namespace PropertyExample {
    internal class Program {
        static void Main(string[] args) {

            try {
                Student stu1 = new Student();
                stu1.SetAge(20);

                Student stu2 = new Student();
                stu2.SetAge(30);

                Student stu3 = new Student();
                stu3.SetAge(50);

                int avgAge = (stu1.GetAge() + stu2.GetAge() + stu3.GetAge()) / 3;
                Console.WriteLine(avgAge);
            } catch(Exception ex) {
                Console.WriteLine(ex.Message);
            }
        }
    }
    class Student {
        private int age;
        public int GetAge() { 
            return this.age; 
        }
        public void SetAge(int value) {
            if(value >= 0 && value <= 120) {//对传入的数据进行范围检测
                this.age = value;
            } else {
                throw new Exception("Age value has error");
            }
        }
    }
}

value在特定的上下文中会作为一个关键字。

C#中的属性的声明,比gettersetter方法更加清晰,调用也比gettersetter方法更加简洁。

namespace PropertyExample {
    internal class Program {
        static void Main(string[] args) {

            try {
                Student stu1 = new Student();
                stu1.Age = 20;

                Student stu2 = new Student();
                stu2.Age = 30;

                Student stu3 = new Student();
                stu3.Age = 50;

                int avgAge = (stu1.Age + stu2.Age + stu3.Age) / 3;
                Console.WriteLine(avgAge);
            } catch(Exception ex) {
                Console.WriteLine(ex.Message);
            }
        }
    }
    class Student {
        private int age;

        public int Age {
            get { return age; } 
            set {
                if (value >= 0 && value <= 120) {//对传入的数据进行范围检测
                    this.age = value;
                } else {
                    throw new Exception("Age value has error");
                }
            }
        }//这段代码就可以替代下面的get和set方法了
        //并且调用属性比调用那两个方法会更为简洁

        public int GetAge() { 
            return this.age;
        }
        public void SetAge(int value) {
            if(value >= 0 && value <= 120) {//对传入的数据进行范围检测
                this.age = value;
            } else {
                throw new Exception("Age value has error");
            }
        }
    }
}

语法糖:将复杂的逻辑,简化成简单明了的逻辑,为的就是方便程序员。

编译器编译属性后,会自动为我们生成,get_Age()set_Age(int32)方法,这就是底层的逻辑。

在这里插入图片描述

属性的声明

在这里插入图片描述

属性完整的声明和简略的声明的区别就在于,访问器

完整的声明属性:

namespace PropertyExample {
    internal class Program {
        static void Main(string[] args) {
            try {
                Student.Amount = 100;
            } catch (Exception ex) {

                Console.WriteLine(ex.Message);
            }
            
        }
    }
    class Student {
        //打出propfull再按两下Tab键,就会自动弹出
        private int age;

        public int Age {
            get { return age; }
            set {
                if (value >= 0 && value <= 120) {//对传入的数据进行范围检测
                    this.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) {
                    Student.amount = value;
                }else { 
                    throw new Exception("Amount must greater than 0."); 
                }
            }
        }
    }
}

简略的声明属性

namespace PropertyExample {
    internal class Program {
        static void Main(string[] args) {
            try {
                Student stu = new Student();
                stu.Age = 100;
            } catch (Exception ex) {

                Console.WriteLine(ex.Message);
            }
            
        }
    }
    class Student {
        //打出prop再按两下Tab键,就会自动弹出属性的简略声明
        public int Age { get; set; }
    }
}

还有一种快速声明属性的办法:

class Student {
    /* 另外一种快速获得属性的办法
     * 在写好私有字段后,将光标移动到字段的名字上
     * 然后打开Edit中的Refactor中的Encapsulate Field
     * 再点击应用,就可以了
     * 有快捷键:按Ctrl+R+E
     */
    private int age;

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

动态地返回值

public bool CanWork {//这个属性可以动态地返回值
    get {
        if(this.Age >= 18) {
            return true;
        } else {
            return false;
        }
    }

当需要get canWork需要被多次调用,而年龄不会被多次调用的时候,

可以提前将canWork计算好,避免每次调用都要去计算,从而损失性能

class Student {
    /* 另外一种快速获得属性的办法
     * 在写好私有字段后,将光标移动到字段的名字上
     * 然后打开Edit中的Refactor中的Encapsulate Field
     * 再点击应用,就可以了
     * 有快捷键:按Ctrl+R+E
     */
    private int age;

    public int Age { get => age;
        set { age = value;
            this.CalcumateCanWork();
        }
    }
    
    private bool canWork;

    public bool CanWork {//这个属性可以动态地返回值
        get {
            return canWork;
        }
       
    }

    private void CalcumateCanWork() {
        if (this.Age >= 18) {
            this.canWork = true;
        } else {
            this.canWork =  false;
        }
    }
}

索引器

在这里插入图片描述

此处是为了演示方便,将索引器作为非集合来使用。

平常应该是,作为集合来使用为更多的。

namespace PropertyExample {
    internal 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>();

        /* 
         * 快速设置索引器
         * 打出indexer,然后按两下Tab键即可
         */
        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 cannot be null.");
                }

                if(this.scoreDictionary.ContainsKey(subject)) {
                    this.scoreDictionary[subject] = value.Value;
                    /* 对于可空类型来说,它的值是Value,
                     */
                } else {
                    this.scoreDictionary.Add(subject, value.Value);
                }
            }
        }
    }
}

常量

在这里插入图片描述

常量在编译的时候,编译器会拿常量的值代替这个常量的标识符。

使用常量,比使用静态属性的性能更高

注意:在这里插入图片描述

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值