c#学习第17课,字段 属性 索引器 常量

一个类型可能具有以下成员:属性 方法 事件 字段 索引器 常量 构造函数 析构函数 运算符 类型

字段(field)

什么是字段?

字段是与对象或类型(类或结构体)相关联的变量,一个字段就是一块数据存放空间

字段是类型的成员旧称"成员变量"

字段分为两种:实例字段和静态字段。实例字段是用来帮助实例或对象存储数据的,隶属于具体某个对象,多个实例字段的组合可以用来表示当前对象或实例的状态,静态字段是用来帮助类型存储数据的,隶属于一个类型,多个静态字段的组合可以用来表示当前类型的状态

class Program
{
  static void Main(string[] args)
  {
    Student stu1 = new Student();
    stu1.Age = 38;
    stu1.score = 96;
  }
  class Student
  {
    public int Age;
    public int score;
  }
}

_ 实例字段具体的只表示一个对象的信息。一个学生的年龄是38岁分数是96分,说明这个学生虽然年纪大了但很努力。这就是实例字段只表示一个具体的某个学生

class Program
{
  static void Main(string[] args)
  {
    Student stu1 = new Student();
    stu1.Age = 38;
    stu1.score = 96;
    Student stu2 = new Student();
    stu2.Age = 13;
    stu2.score = 54;
    Console.WriteLine(Student.Amount);
  }
  class Student
  {
    public int Age;
    public int score;
    public static int Amount;
    public Student()
    {
      Amount++;
    }
  }
}

__ 静态字段,表示具体某一个类型的信息。它代表学生这个名词的信息表示的是所有学生的信息。Amount是数量表示的是有几个学生,创建了两个学生实例所以是2个学生。下面再用静态字段表示学生的平均值

class Program
{
  static void Main(string[] args)
  {
    List ListStu = new List();
    for(int i = 0;i < 100;i++)
    {
      Student stu1 = new Student();
      stu1.Age = 24;
      stu1.Score = i;
      stu1.Amount++;
      ListStu.Add(stu1);
    }  
    int TotalAge = 0;
    int TotalScore = 0;
    foreach(var stu1 in ListStu)
    {
      TotalAge += stu1.Age;
      TotalScore += stu1.Score;
    }
    Student.AverageAge = TotalAge/stu1.Amount;
    Student.AverageScore = TotalSroce/stu1.Amount;
    Student.ReportAverageAge();
    Student.ReportAverageScore();
    Student.ReportAmount();
  }  
}
class Student
{
  public int Age;
  public int Score;
  public static int Amount;
  public static int AverageAge;
  public static int AverageScore;
  public statoc void ReportAmount()
  {
    Console.WriteLine(Amount);
  }
  public static void ReportAverageAge()
  {
    Console.Writeline(AverageAge);
  }
  public static void ReportAverageScore()
  {
    Console.Writeline(AverageScore);
  }
}

字段的声明

_ 声明静态字段使用static修饰符,且声明静态字段的标识符一定要是名词

field-declaration:
            attributes(opt)  field-modifiers(opt)  type variable-declarators//按顺序依次为“可选特性” “可选修饰符” “数据类型” “变量声明器”
//字段声明语法

_ 字段的修饰符有:new public protected internal private static readonly volatile。可以使用多个修饰符来组成有意义的字段声明。有readonly修饰符的字段叫做只读字段,只读字段一但被初始化之后就不能够再进行赋值

字段的初始化时机

_ 字段的初始化时机可以理解为初始化器什么时候对值进行初始化?

_ 实例字段的初始化在创建这个实例的时候就会进行一次初始化。

_ 静态字段的初始化只有在运行环境加载数据类型的时候才会进行初始化,当数据类型被加载的时候它的静态构造器会被调用。因为数据类型只会被加载一次所以静态构造器也只会执行一次也就是静态字段只会初始化一次

_ 声明静态构造器相比声明实例构造器不需要public修饰符但需要static修饰符。无论是实例构造器还是静态构造器都可以在内部输入字段的初始化逻辑,也可以在声明字段的时候添加初始化器。如果你没有对字段添加初始化器和添加构造器那么编译器会自动添加默认的构造器,被默认构造器初始化的字段的默认值就是其数据类型的默认值

属性

_ 属性用于表示类型或对象的特征,特征反映状态。

属性是由字段扩展(进化)而来,两者有很多相似的地方。从它们的声明中看字段更偏向于对象实例在内存中的布局,属性偏向于对象实例在现实世界的特征。(我个人认为最后一句话的意思是:字段存储的数据是其数据类型所包含的所有值,符合的是程序世界的逻辑。但某些字段存储的数据放在现实世界中并不可能发生,不符合常理。而属性更贴合现实世界的逻辑,也就是存储的数据在现实世界中是符合常理的)

class Program
{
  static void Main(string[] args)
  {
    Person ren = new Person();
    ren.Age = 2000000000;
  }
}
class Person
{
  public int Age;
}

_ 假设有一个“人”类,它有一个“年龄”的字段,它可以表达的最大年龄取决于它的数据类型的最大值,假如它是int类型的字段那么它可以表达的最大年龄可以输入为几亿岁甚至可以为负几亿岁,那么这个字段存储的数据现实吗?并不现实。于是微软为了字段不被这种“非法值”污染而推出了属性 _

class Program
{
  static void Main(string[] args)
  {
    Person ren1 =new Person();
    ren1.SetAge = 35;
    Person ren2 =new Person();
    ren2.SetAge = 25;
    Person ren3 =new Person();
    ren3.SetAge = 15;
    int avgAge = (ren1.GetAge+ren2.GetAge+ren3.GetAge)/3;  
  }
}
class Person
{
  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 bug")
      }
    }
  }
}

_ 最初的属性由Get和Set方法对实现,后来因为太过繁琐而对属性进行了由繁入简的优化

_如果说字段是存储数据的容器那么属性就是对字段进行封装或者说设置逻辑(对数据进行筛选)

class Program
{
  static void Main(string[] args)
  {
    Person ren1 = new Person();
    ren1.Age = 20;
  }
}
class Person
{
  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");
      }
    }
  }
}

属性有三种,一种是get,set访问器都有的叫做读写属性,第二种只有get访问器的叫只读属性,第三种只有set访问器的叫做只写属性。不过一般不会怎么见到只写属性,因为使用属性基本就是为了得到一个安全的数据,而没有了get访问器就无法读取数据不能对外“暴露数据”

属性是一个语法糖,语法糖是一小段简单的代码背后隐藏复杂的逻辑

属性的声明

property-declaration:
  attributes(opt) property-modifiers(opt) type member-name{accessor-declarations}//属性声明语法

无论字段是静态的还是实例的它的属性都要与之保持一致

声明完整属性快捷键"propfull+两下tab键",声明简略属性快捷键"prop+两下tab键"

简略属性和一个公有的字段相似,没有保护措施所以也会被非法值所“污染”,一般简略属性用于传递数据
public int Age{get; set;}//简略属性

属性相比于字段更高级的一个功能就是是可以实时进行动态运算数据。下面有一个例子,根据国家法律规定未满16周岁不可以进行工作,我们要检测学生是否有16周岁

class Program
{
  static void Main(string[] args)
  {
    Student stu1 = new Student();
    stu1.Age = 15;
    Console.WriteLine(stu1.CanWork);
  }
}
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");
      }
    }
  }
  public bool CanWork
  {
    get//只读属性
    {
      if(this.age>=16)
      {
        return true;
      }
      else
      {
        return false;
      }
    }
  }
}

可以看到CanWork属性并没有封装字段,而当我们从外界调用它的时候,他返回的值是经过它内部逻辑运算之后产生的值

代码的编写根据现实的业务逻辑来决定,如上述代码CanWork值需要主动进行运算,就可以应用在age值访问频繁和CanWork值偶尔访问的场景里。但如果每个学生都要检测是否满16周岁,每次都需要访问CanWork属性进行运算,应用上述代码就会浪费计算性能

class Program
{
  static void Main(string[] args)
  {
    Student stu1 = new Student();
    stu1.Age = 16;
  }
}
class Studebt
{
  private int age;
  public int Age
  {
    get
    {
      return age;
      this.CalculatorCanWork();
    }
    set
    {
      if(value>=0 && value<=120)
      {
        age =value;
      }
      else
      {
        throw new Exception("age value has error");
      }
    }
  }
  private bool canWork;
  public bool CanWork
  {
    get{return canWork;}
  }
  private void CalculatorCanWork()
  {
    if(age>=16)
    {
      canWork = true;
    }
    else
    {
      canWork = false;
    }
  }
}

观察上述代码可以得知在每次给Age赋值的时候都会被动的给CanWork进行运算。根据业务逻辑的不同来选择恰当的逻辑编写程序

索引器

索引器用于使对象可以使用与数组相同的方式(下标)进行索引

索引器一般只会出现在集合类型里
声明索引器快捷键:ind+两下tab

常量

常量是用来表示“常量值”(在编译器编译代码的时候会把常量的标识符替换成常量的值从而提升程序运行效率)

常量声明和字段的声明相似,不过要添加“const”修饰符。常量只隶属于类型,所以没有实例常量,不过可以用实例只读字段来当做“实例常量”

常量分为两种,一种是成员常量还有一种是局部常量。成员常量就是在类型里面作为类型的成员。局部变量用来参与组成方法体当中的算法

各种“只读”的应用场景

提高程序可读性和执行效率——常量
防止对象的值被更改——只读字段
向外暴露不允许修改的数据——只读属性(静态或非静态)
当希望成为常量的值的类型不被常量接受时(类或自定义结构体)——静态只读字段

你可能感兴趣的:(笔记,学习,c#)