017 字段、属性、索引器、常量 · 语雀https://www.yuque.com/yuejiangliu/dotnet/timothy-csharp-017
程序=数据+算法
字段,属性,索引器,常量都是表示数据的
C#类型所具有的成员:
字段√
属性√
索引器√
常量√
方法
事件
构造函数
析构函数
运算符
类类型
字段-成员变量
实例字段-对象
static字段-类
字段初始化的时机
无显式初始化时,字段获得其类型的默认值
值类型-按位归0
引用类型-null
实例字段在对象创建时被加载
static字段在类被加载时,static字段只能被初始化1次,在类被加载时,会调用static构造器,而且static构造器只能被调用1次,所以static初始化可以使用初始化器(=xxx)显式初始化或者在static构造器中初始化
readonly只读字段-为实例/类型保存希望一旦被初始化后就不希望再改变的值
实例只读字段-只有1次机会被赋值-在构造器中,使用带参的构造器
static只读字段-只有1次机会被初始化-在static构造器中
//实例字段和static字段
//readonly字段
using System.Collections.Generic;
namespace cstimothy171
{
class Program
{
static void Main(string[] args)
{
List stuList = new List();
for (int i = 0; i < 100; i++)
{
Student stu = new Student(i);
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 readonly int ID;
public int Age=0;
public int Score=0;
public static int AverageAge;
public static int AverageScore;
public static int Amount;
public Student(int id)
{
Student.Amount++;
this.ID = id;
}
static Student()
{
Student.Amount = 0;
Student.AverageAge = 0;
Student.AverageScore = 0;
}
~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);
}
}
}
字段由来
字段在cyy已经存在
cyy-cpp-java-c#
字段声明
特性opt+有效的修饰符组合opt+数据类型type+变量声明器;
有效的修饰符组合
public static int Amount;
public readonly int ID;
public static readonly
变量声明器:
1.变量名
2.变量名+变量的初始化器
变量名=初始值
在声明时显式初始化和在构造器中进行初始化效果相同
属性-属性是字段的自然扩展
对外-暴露数据,数据可以是存储在字段里的,也可以是动态计算出来的
对内-保护字段不被非法值污染
属性由Get/Set方法对进化而来
字段->属性:
属性由get/set方法对进化而来
//namespace cstimothy172
//{
// class Program
// {
// static void Main(string[] args)
// {
// try
// {
// Student stu1 = new Student();
// stu1.SetAge(20);
// Student stu2 = new Student();
// stu1.SetAge(20);
// Student stu3 = new Student();
// stu1.SetAge(200);
// 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");
// }
// }
// }
//}
namespace cstimothy173
{
class Program
{
static void Main(string[] args)
{
try
{
Student stu1 = new Student();
stu1.Age = 20;
Student stu2 = new Student();
stu2.Age = 20;
Student stu3 = new Student();
stu3.Age = 200;
int avgAge = (stu1.Age+ stu2.Age+ stu3.Age) / 3;
Console.WriteLine(avgAge);
}
catch (Exception ex)
{
Console.WriteLine(ex.Message);
}
}
}
class Student
{
//propfull
//value是上下文关键字
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");
}
}
}
}
}
属性的声明
完整声明propfull-后台变量和访问器
简略声明prop-只有访问器-不受保护,只为传递数据用
特性opt+有效的修饰符组合+type+属性名{访问器}
public static
只读属性-只有get没有set
属性有get和set,但是set为private,只能在类体内赋值
只写属性-只有set没有get-less
属性是字段的包装器
永远使用属性来暴露数据
字段永远都是private或protected的
委托是方法的包装器
//属性
//实例属性和static属性
namespace cstimothy174
{
class Program
{
static void Main(string[] args)
{
try
{
Student.Amount = -1;
}
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");
}
}
}
//static属性
private static int amount;
public static int Amount
{
get { return amount; }
set
{
if (value >= 0)
{
amount = value;
}
else
{
throw new Exception("Amount must greater than 0");
}
}
}
}
}
//属性的set为private-只能在类体内赋值
//不同于只读属性-没有set
namespace cstimothy175
{
class Program
{
static void Main(string[] args)
{
Student stu = new Student();
stu.SomeMethod(1);
Console.WriteLine(stu.Age);
}
}
class Student
{
private int age;
public int Age
{
get { return age; }
private set { age = value; }
}
public void SomeMethod(int x)
{
this.age = x;
}
}
}
动态计算值的属性
主动计算
被动计算
//动态计算值的属性-主动计算
//适用于CanWork使用频率低的场景,Age设定频繁的场景
namespace cstimothy176
{
class Program
{
static void Main(string[] args)
{
try
{
Student stu = new Student();
stu.Age = 12;
Console.WriteLine(stu.CanWork);
}
catch (Exception ex)
{
Console.WriteLine(ex.Message);
}
}
}
class Student
{
private int age;
public int Age
{
get { return age; }
set { age = value; }
}
//CanWork属性并没有封装字段
//它的值是实时动态计算出来的
public bool CanWork
{
get
{
if (this.age >= 16)
{
return true;
}
else
{
return false;
}
}
}
}
}
//动态计算值的属性-被动计算
//适用于canWork使用频繁的场景,每次设定Age时就计算canWork
namespace cstimothy177
{
class Program
{
static void Main(string[] args)
{
try
{
Student stu = new Student();
stu.Age = 12;
Console.WriteLine(stu.CanWork);
}
catch (Exception ex)
{
Console.WriteLine(ex.Message);
}
}
}
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;
}
}
}
}
索引器能够使对象能够能下标进行访问
一般拥有索引器的都是集合类型
此时example为讲解方便,使用非集合类型
声明索引器-indexer tab*2
//索引器
using System.Collections.Generic;
namespace cstimothy178
{
class Program
{
static void Main(string[] args)
{
Student stu = new Student();
var mathScore = stu["Math"];
Console.WriteLine(mathScore==null);
stu["Math"] = 90;
stu["Math"] = 100;
mathScore = stu["Math"];
Console.WriteLine(mathScore);
}
}
class Student
{
//私有字段
private Dictionary dict = new Dictionary();
//index tab*2
//此处返回值为int?-可空的int类型
public int? this[string subject]
{
get
{
if (this.dict.ContainsKey(subject))
{
return this.dict[subject];
}
else
{
return null;
}
}
set
{
//因为返回值为可空类型,所以上来先判断
if (value.HasValue == false)
{
throw new Exception("score cannot be null");
}
if (this.dict.ContainsKey(subject))
{
this.dict[subject] = value.Value;
}
else
{
this.dict.Add(subject, value.Value);
}
}
}
}
}
常量
Math.PI
public const double PI=3.14159
int.MaxValue
public const int MaxValue
int.MinValue
public const int MinValue
常量隶属于类型而不是对象,没有实例常量
类型.常量
实例常量由只读实例字段来担当-只有1次机会初始化,在声明的时候,初始化器初始化or在构造器中初始化
成员常量和局部常量
成员常量
Math.PI
public const string WebsiteURL= "xxx";
局部常量-在方法体中-const int x=100;
只读的应用场景
1.常量-在编译器的时候会用常量的值代替常量标识符
成员常量
局部常量
2.只读字段-没有实例常量,为了防止对象的某个值被修改则使用只读字段
3.只读属性-向外暴露不允许修改的数据
对象-实例只读属性
类型-static只读属性-只有get没有set-区别与set为private的属性
4.静态只读字段
常量的数据类型只能是基本数据类型
不能用类类型作为常量的类型-此时使用静态只读字段-static readonly
//常量
namespace cstimothy179
{
class Program
{
static void Main(string[] args)
{
Console.WriteLine(Student.WebsiteURL);
}
}
class Student
{
//成员常量
public const string WebsiteURL= "xxx";
//静态只读字段
public static readonly Building Location = new Building("some address");
}
class Building
{
public string Address { get; set; }
public Building(string address)
{
this.Address = address;
}
}
}