using System; using System.Collections.Generic; using System.Linq; using System.Text; using System.Threading.Tasks; namespace AllTest { class Program { static void Main(string[] args) { CTest tObj = new CTest("D1654978979r7ew9rqewr"); Console.WriteLine(tObj.Name); Indexer idx = new Indexer(); idx[0] = "Mike"; Console.WriteLine(idx[0]); } } // 方法签名组成信息:方法名、形参数量、形参数据类型和顺序、形参修饰符(返回类型和形参名,不属于签名) // 方法重载:一个类中(即同一个作用域),方法名相同,签名不同(或者说参数列表不同)的两个或多个方法之间构成重载 class CTest { // ----------------------------------------------------------构造器-------------------------------------------------------------- // // >>> // 实例构造器--类似C++的构造函数 // 实例构造器在每次创建实例对象时都会被调用,一般用于对实例字段做初始化 public CTest(string cardId) { // 在实例构造器里面对实例字段初始化和在字段定义时直接初始化是一样的,一般统一用一种风格初始化即可,比如都在定义时初始化 // C++里面对成员变量初始化其实是在进入构造函数体之前的构造函数初始化列表,函数体内只是重新赋值并不叫初始化。 // C#不一样,它不允许使用初始化列表对字段初始化(可以写上去试试,会有报错提示),它的初始化列表只用于调用其他构造器,如this(...), base(...) //this.Id = 0; //this.Name = ""; // 只读字段初始化 CardId = cardId; // 注意:这里并不是对静态字段做初始化,只是对静态字段的重新赋值,静态字段只在静态构造器或者定义时初始化 //ObjectCount = 100; // error:常量不允许在实例构造器里面初始化,因为它是常量,且是与类型关联的 // ConstantVar = 0; } // >>> // 静态构造器 // 静态构造器只在类型第一次被加载时调用一次,一般用于对静态字段做初始化 static CTest() { // 同样的,普通静态字段也可以直接在定义时初始化,这是等价的 ObjectCount = 0; // 静态只读字段 Rate = 0.04; } // ----------------------------------------------------------构造器-------------------------------------------------------------- // // --------------------------------------------------------字段(field)--------------------------------------------------------- // // >>> // 实例字段是与类型创建的对象关联的字段用于表征对象的某种状态,可以在定义(或者叫声明)时直接初始化也可以在实例构造器中初始化 // 普通实例字段 public int Id = 0; // 定义时初始化 public string Name;// 不初始化它将被赋予string类型的默认值,编译器提示:warning CS0649: Field 'CTest.Name' is never assigned to, and will always have its default value null // 实例只读字段 public readonly string CardId; // >>> // 只读字段都是有且仅有一次初始化机会,初始化之后就再也不能更改,类似C++的const成员变量(但是并不一样) // 只读字段一般在对应的构造器里面初始化,同样也可以在定义时直接初始化 // >>> // 静态字段是与类型关联的字段,所有实例共享,可以在定义时直接初始化也可以在静态构造器中初始化。访问静态字段时必须使用类型+"."的形式,如CTest.ObjectCount // 普通静态字段 public static int ObjectCount; // 静态只读字段 public static readonly double Rate; // -------------------------------------------------------字段(field)------------------------------------------------------- // // ------------------------------------------------------属性(property)----------------------------------------------------- // // >>> // 属性:一种用于访问对象或者类型的特征的成员,特征反应了状态 /* 属性是对字段的自然扩展: * 字段更偏向于表示对象的内存布局,而属性更偏向于反映现实世界中对象的特征 * 属性说白了就是对字段的封装和保护,就是一种语法糖封装了字段的Set/Get访问方法(使用反编译器ILdasm可以查看属性背后生成的IL代码) */ // 实例属性(对应字段为实例字段) private int number = 0; public int Number { // get访问器:可以添加实时计算返回逻辑 get { return number; } // set访问器:可以添加逻辑判断 set { // value是一个上下文关键字,表示用户当前设置的值 if (value > 0 && value < 10000) { number = value; } else { throw new Exception("invalid value!"); } } } // 静态属性(其对应字段也必须是静态的) private static int amount; public static int Amount { get { return amount; } set { if (value > 0 && value <= 999) { amount = value; } } } // 只读属性 public int rdNum; public int RdNum { get { return rdNum; } } // 只允许从类内部修改的属性 private string specialProp; public string SpecialProp { get { return specialProp; } // 私有的set访问器 private set { if (!string.IsNullOrEmpty(value)) { specialProp = value; } } } // 简略声明属性 // 这种属性用起来和public字段没区别,但是查看IL代码可知,后台创建了对应的实例字段 // 这种属性一般用来传递数据,因为其set访问器没有任何保护逻辑 public string StrConf { get; set; } // 属性和字段的关系:建议永远使用属性来暴露数据,而字段应该设为private或protected // ------------------------------------------------------属性(property)----------------------------------------------------- // // ------------------------------------------------------常量(constant)----------------------------------------------------- // // 常量是表示常量值(即在编译时计算的值,编译时使用这个值来代替常量对应的那个标识符)的类成员,成员常量隶属于类型,没有实例常量("实例常量"的伪角色可以使用实例只读字段来担当,但是只读字段本质上还是一个变量) // 成员常量行为很像静态字段,所有类的实例共享,即使没有实例也可以使用。和静态字段不同的是,常量没有自己的存储位置,而是在编译时被编译器替换,类似C/C++中的#define宏(C++中的const类成员不允许通过类名直接访问,必须有实例,除非有static修饰) // 常量的类型只能是一些基本数据类型(简单类型)如intdouble,必须在编译时可求值,只能在声明时初始化 // 常量有成员常量和局部常量(在方法体内定义的)之分,C#中函数参数不允许const修饰,常量不允许static修饰 // 访问成员常量时必须使用类型+"."的形式,如CTest.ConstantVar /*运用场景: 提高程序可读性和执行效率--常量 防止对象的值被改变--只读字段 向外暴露不允许修改的数据--只读属性(静态或非静态) 某些类型如类/自定义结构体不能声明为常量,但是如果想让其功能类似常量可以使用静态只读字段。eg: public const Indexer indx = new Indexer(); // error */ public const int ConstantVar = 9999; // 声明时就必须提供初值 // ------------------------------------------------------常量(constant)----------------------------------------------------- // } // ------------------------------------------------------索引器----------------------------------------------------- // // 索引器说白了就是类似C++重载了[]的类,在C#中一般用于集合类型的类 class Indexer { // 借助(委托)一个集合类来实现索引器 private Dictionary<int, string> employeesDic = new Dictionary<int, string>(); // 索引器 public string this[int id] { get { if (this.employeesDic.ContainsKey(id)) { return this.employeesDic[id]; } else { return null; } } set { // 首先判断设置的值是否合法 if (string.IsNullOrEmpty(value)) { throw new Exception("invalid value!"); } if (this.employeesDic.ContainsKey(id)) { this.employeesDic[id] = value; // 已存在则修改 } else { this.employeesDic.Add(id, value); // 不存在则添加 } } } } // ------------------------------------------------------索引器----------------------------------------------------- // }