1.类成员
类成员分数据成员和函数成员,数据成员用于保存数据,函数成员用于执行代码。
2. 成员修饰符
[特性] [修饰符] 核心声明
特性:如果有特性,必须放在修饰符和核心声明之前;如果有多个特性,可任意顺序
修饰符:如果有修饰符,必须放在核心声明前;如果有多个修饰符,可任意顺序
static private int TestCount = 10;
private static int TestCount = 10; 这2中声明式等效的。
3. 实例成员
类成员可以关联到类的一个实例。类的每个实例拥有自己的各个类成员的副本—实例成员。改变一个实例字段的值不会影响任何其它实例中成员的值。
class MyDemoClass
{
public int TestValue;
}
class Program
{
static void Main(string[] args)
{
MyDemoClass d1 = new MyDemoClass();
d1.TestValue = 123;
MyDemoClass d2 = new MyDemoClass();
d2.TestValue = 456;
Console.WriteLine($"d1 value:{d1.TestValue}, d2 value:{d2.TestValue}");
}
}
输出:
d1 value:123, d2 value:456
实例变量至于对应的实例关联 ,类的实例都有自己字段的副本。
4. 静态字段
静态字段被类的所有实例共享,所有实例都访问同一内存位置。
使用static 修饰符将字段声明为静态
class MyDemoClass
{
public int TestValue;//实例字段
public static int StaticValue=999;//静态字段
}
5. 从类的外部访问静态成员
类名+点+成员名称 (MyDemoClass.StaticValue)
静态成员的生存周期
与实例成员不同,实例成员只有实例创建后才产生,实例销毁后实例成员就不存在了。
静态成员,即使没有实例,也存在,并可以访问。
6. 静态函数成员
静态函数成员也是独立于任何类实例的,即使没有实例,仍可以调用静态方法。
静态函数不能访问实例成员,但能访问其它静态成员。
class Demo
{
static public int x;// 静态字段
static public void PrintX()//静态方法
{
Console.WriteLine($"Value of X:{x}");
}
}
测试:
class Program
{
static void Main(string[] args)
{
Demo.x = 66;//使用句点语法
Demo.PrintX();//使用句点语法
}
}
7. 其它静态类成员类型
可声明为静态的类成员类型
8. 成员常量
成员常量类似本地常量,只是它被声明在类中,而不是在方法内。
初始化成员常量的值在编译时必须是可计算的,而且通常是一个预定义简单类型或者他们组成的表达式。
在类中声明:
const int Val = 100;// 定义int 类型常量,初始值100
与C,C++不同,在C#中没有全局常量,每个常量都必须声明在类中。
const int IntVal;// 错误,必须初始化
IntVal=100;//错误,不允许赋值
9. 常量与静态量
成员常量:表现想静态只,但不能使用 static声明。与静态常量不同,没有自己的存储位置,而是编译时被编译器替换。
静态常量
public const double PI = 3.1415;// 常量
使用:类名.PI
10. 属性
属性是代表类的实例或者类中的一个数据项的成员。
属性与字段类型,有如下特征:
它是命名的类成员
它有类型
它可以被赋值和读取
然而字段只属于一个函数成员,它不为数据存储分配内存空间
属性是指定的一组2个匹配的,访问器的方法:
set访问器为属性赋值,get访问器从属性取值。
属性声明和访问器
class Demo
{
private int FiledValue;//字段,分配内存(后备字段)
public int MyValue //属性,未分配内存
{
set { FiledValue = value; }
get { return FiledValue; }
}
}
使用属性
Demo d = new Demo();
d.MyValue = 20;//Set 赋值
Console.WriteLine($"{d.MyValue}");
属性和关联字段
常见的方式是在类中将字段声明为private以封装字段,并声明一个public熟悉控制从类外部对该字段的访问。
和熟悉关联的字段常被称作后备字段或后备存储。
属性定义的2中常见方式,使用Pascal大小写,Camel大小写版本
private string name;
public string Name
{
get { return name; }
set { name = value; }
}
private string _name;
public string Name
{
get { return _name; }
set { _name = value; }
}
执行其它计算
访问器get,set 能执行任何计算,也可以不执行任何计算,唯一需求行为是get访问器需要返回一个属性类型的值。
public int MyValue
{
set { }//什么也不设置
get { return 100; }//只是返回100
}
private int _myValue2;
public int MyValue2
{
get { return _myValue2; }
set
{
MyValue2 = value > 100 ? 100 : value;//条件运算
}
}
C# 7.0引入了另一种语法,表达式函数体(Lambda表示)
private int score;
private int Score
{
set => score>100?100 : value;
get => score;
}
只读和只写属性
只有get 访问器的属性称为只读属性
只有set访问器的属性称为只写属性(很少见,几乎没有实际用途)
两个访问器中至少有一个必须定义,否则编译器产生错误。
属性与共有字段
属性是函数成员,而不是数据成员,允许输入输出。
属性可以是只读或只写,字段不可以。
编译后的变量和编译后的属性语义不同。
自动实现属性
只声明属性,不声明后备字段。编译器自动创建隐藏后备字段。
public string lastName { get; set; }
静态属性
属性声明为static,和静态成员一样:
不能访问类的实例成员,但能被实例成员访问。
不管类是否有实例,它们都是存在的。
在类的内部,可以仅使用名称来引用静态属性。
class Test
{
public static int MyValue { get; set; }
public void PrintValue()
{
Console.WriteLine($"Value from inside:{MyValue}");// 类的内部访问
}
测试:
//类的外部访问
Console.WriteLine($"Initial Value:{Test.MyValue}");
Test.MyValue = 20;
Console.WriteLine($"New Value:{Test.MyValue}");
11. 实例构造函数
实例构造函数是一个特殊的方法,它在创建类的每个新实例时执行。
构造函数用于初始化类实例的状态
如果需要从类的外部创建类的实例,需要声明为public
构造函数的名称和类同名
构造函数不能有返回值
带参数的构造函数
构造函数可以带参数
构造函数可以被重装
public class Demo
{
int id;
string name;
public Demo() { id = 1; name = "name1"; }// 无参构造函数
public Demo(int ID) { id = ID; name = "testName2"; }//带一个参数的构造函数
public Demo(int Id,string Name) { id = Id; name = Name; }//带2个参数的构造函数
public void ShowMessage()
{
Console.WriteLine($"Name:{name}, Id:{id}");
}
}
测试上演示类:
class Program
{
static void Main(string[] args)
{
Demo d1 = new Demo();
d1.ShowMessage();
Demo d2 = new Demo(123);
d2.ShowMessage();
Demo d3 = new Demo(456, "MyName");
d3.ShowMessage();
}
}
默认构造函数
没有参数;方法体为空
如果类声明了任何构造函数,编译器就不会创建默认的构造函数。
静态构造函数
构造函数也可以声明为static,实例构造函数初始化类的每个实例,而静态构造函数初始化类级别的项。通常静态构造函数初始化类的静态字段。
类只能有且只能有一个构造函数,且不能带有参数,静态构造函数不能有访问修饰符。
类即可有静态构造函数,也可以有实例构造函数。
静态构造函数不能访问任何实例成员,因此也不能使用this访问器
不能从程序中显示调用静态构造函数,系统会自动调用它们。
class RandomNumber
{
private static Random RandomKey;//私有静态变量
static RandomNumber() // 静态构造函数
{
RandomKey = new Random();
}
public int GetRandKeyNumbers()
{
return RandomKey.Next();
}
}
测试调用:
class Program
{
static void Main(string[] args)
{
RandomNumber rndN1 = new RandomNumber();
RandomNumber rndN2 = new RandomNumber();
Console.WriteLine($"Next Random #{rndN1.GetRandKeyNumbers()}");
Console.WriteLine($"Next Random #{rndN2.GetRandKeyNumbers()}");
}
}
输出:
Next Random #365872672
Next Random #1403081881
对象初始化语句
new TypeName {Field1=InitExpr1, Filed2=InitExpr2} //对象初始化语句
new TypeName(ArgList) {Field1=InitExpr1, Filed2=InitExpr2} //成员初始化语句
析构函数
析构函数destructor 执行的类在实例被销毁之前需要的清理或释放非托管资源的行为。
readonly 修饰符
const字段只能在字段的声明语句中初始化,而readonly字段可在如下任意位置设置:
字段声明语句
类的任何构造函数
const字段的值必须可在编译时决定,而readonly字段的值可在运行时决定。
const的行为总时静态的,对于readonly字段可以是静态字段,也可是实例字段,在内存中有存储位置。
readonly double PI=3.1415;
12. This 关键字
对当前实例的引用,只能被用在下列类成员的代码块中:
实例构造函数
实例方法
属性和索引器的实例访问
所以不能在任何静态函数成员的代码中使用。
使用this的目的:
用于区分类的成员和局部变量或参数。
作为调用方法的实参。
13. 索引器
什么是索引器:索引器是一组get和set访问器,与属性类似。
索引器和属性:
索引器和属性一样不用分配内存来存储
索引器和属性都主要被用来访问其它数据成员。
属性通常表示单个数据成员,索引器通常表示多个数据成员。
声明索引器:
索引器没有名称。在名称的位置是关键字this。参数列表在方括号中间;参数列表中必须至少声明一个参数。
ReturnType this[Type param,...]
{
get {...}
set {...}
}
索引器的set 访问器
当索引器被用于赋值时,set访问器被调用。
索引器的get 访问器
当索引器获取值时,可以通过一个或多个参数调用get访问器。
不能显示调用get,set访问器。
class Employee
{
public string FirstName;
public string LastName;
public string CityOfBirth;
//以上代码是没有索引的简单类
//声明一个索引器
public string this[int index]
{
set
{
switch (index)
{
case 0:
FirstName = value;
break;
case 1:
LastName = value;
break;
case 2:
CityOfBirth = value;
break;
default:
throw new ArgumentOutOfRangeException("index");
}
}
get
{
switch (index)
{
case 0:
return FirstName;
case 1: return LastName;
case 2: return CityOfBirth;
default:
throw new ArgumentOutOfRangeException("index");
}
}
}
}
测试代码:
class Program
{
static void Main(string[] args)
{
Employee ep = new Employee();
ep.FirstName = "Jane";
ep.LastName = "Doe";
ep.CityOfBirth = "Dallas";
Console.WriteLine($"{ep.LastName} {ep.FirstName} {ep.CityOfBirth}");
// 使用索引器
Console.WriteLine($"{ep[0]} {ep[1]} {ep[2]}");
}
}