C#学习笔记(4)深入理解类上
4,1成员修饰符的顺序
在前面的内容中,你看到字段和方法的声明可以包括如public和private这样的修饰符。
类成员声明语句由下列部分组成:核心声明、一组可选的修饰符和一组可选的特性(attribute用于描述这个结构的语法如下。方括号表示方括号内的成分是可选的。
[特性] [修饰符] 核心声明
可选成分如下。
修饰符:
(1)如果有修饰符,必须放在核心声明之前。
(2)如果有多个修饰符,可以任意顺序排列。
特性
(1)如果有特性,必须放在修饰符和核心声明之前。
(2)如果有多个特性,可以任意顺序排列。
至此,只解释了两个修饰符,即public和private。以后会介绍特性。例如,public static都是修饰符,可以一起修饰某个声明。因为它们都是修饰符,所以可以任何顺序放置。两行代码在语义上是等价的;
public static int MaxVal;
static public int MaxVal;
4.2静态字段
静态字段被类的所有实例共享,所有实例都访问同一内存位置。因此,如果该内存位置的值被一个实例改变了,这种改变对所有的实例都可见。
可以使用static修饰符将字段声明为静态,如:
class D
(
int Mem1; //实例字段
static int Mem 2; //静态字段
)
例如,上面代码声明了类D,它含有静态字段Mem2和实例字段Mem1。Main定义类D的两个实例。静态成员Mem 2是与所有实例分开保存的。并且从实例内部,访问或更新静态字段的语法和访问或更新其他成员字段一样。
因为Mem2是静态的,所以类D的两个实例共享一个Mem2字段。如果Meme2被改变了,个改变在两个实例中都能看到。成员Mem 1没有声明为static,所以每个实例都有自己的副本。
4.3 从类的外部访问静态成员
方法一:
就像实例成员,静态成员也可以使用点运算符从类的外面进行访问,但因为没有实例,所以访问静态成员的方法使用类名
形如
class D {
static int Mem;
……
}
D.Mem = Value; //访问静态成员
代码:
using System; class A { public const int N = 10010; public static void display() { Console.WriteLine($"N = {N}"); } } class Program { static void Main() { Console.WriteLine($"A.N = {A.N}"); A.display(); } }
运行结果:

方法二:
使用using static声明,在该成员所属的类中包含一个using static声明。
样例如下
using static System.Console;
…………
WriteLine(“$hello world”);
静态成员的生存周期(静态成员的生命期与实例成员的不同):
只有在实例创建之后才产生实例成员,在实例销毁之后实例成员也就不存在了。但是即使类没有实例,也存在静态成员,并且可以访问。
4.4静态函数成员
(1)如同静态字段,静态函数成员独立于任何类实例。即使没有类的实例,仍然可以调态方法。
(2)静态函数成员不能访问实例成员,但能访问其他静态成员。
访问静态函数的方法与访问静态字段一致。
4.5其他静态类成员类型
方法√ 属性√ 构造函数√ 运算符√ 索引器× 事件√
字段√ 类型√ 常量×
4.6成员常量
特别说明:与C和C++不同,在C#中没有全局常量。每个常量都必须声明在类型内。
成员常量类似前一章所述的局部常量,只是它们被声明在类声明中而不是方法内,如下面的示例:
class MyClass
{
const int IntVal=100;//定义int类型常量
}
const double PI=3.1416;//错误:不能在类型声明之外声明
成员常量与前面讲的局部常量几乎一致不过是声明在类中。
4.7属性
4.7.1属性概述
属性是代表类实例或类中的数据项的成员。使用属性就像写入或读取一个字段,语法相同。
属性的特征:
(1)属性是命名的类成员。
(2)属性有类型。
(3)属性可以被赋值和读取。
(4)属性不一定为数据存储分配内存!
(5)属性会执行代码。
属性是一组(两个)匹配的、命名的、称为访问器的方法。
(1)set访问器为属性赋值。
(2)get访问器从属性获取值。
4.7.2属性声明和访问器
set和get访问器有预定义的语法和语义。可以把set访问器想象成一个方法,带有理参数,它“设置”属性的值。get访问器没有参数并从属性返回一个值。
set访问器:
(1)拥有一个单独的、隐式的值参,名称为value,与属性的类型相同;
(2)拥有一个返回类型void。
get访问器:
(1)没有参数;
(2)拥有一个与属性类型相同的返回类型;
形如:
Set与get说明:
set访问器中的隐式参数value是一个普通的值参。和其他值参一样,可以用它发送双数据到方法体或访问器块。在块的内部,可以像普通变量那样使用value,包括对它赋值。
get访问器的所有执行路径必须包含一条return语句,它返回一个属性类型的值。
访问器set和get可以以任何顺序声明,并且,除了这两个访问器外,属性上不允许有其他方法
4.7.3属性的示例
下面的代码展示了一个名为C1的类的声明示例,它含有一个名为MyValue的属性。
请注意,属性本身没有任何存储。取而代之,访问器决定如何处理发送进来的数据,以及
应将什么数据发送出去。
在代码之前在介绍一下如何使用属性:
要写入一个属性,在赋值语句的左边使用属性的名称。
要读取一个属性,把属性的名称用在表达式中。
例如,下面的代码包含一个名为MyValue的属性的声明。只需使用属性名就可以写入和读取属性,就好像它是一个字段名。
int MyValue//属性声明
{
set{ ...}get{…‥}
}
MyValue= 5;//赋值: 隐式调用set方法
z = MyValue;//表达式: 隐式调用get方法
属性会根据是写入还是读取来隐式地调用适当的访问器。不能显式地调用访问器,因为这样做会产生编译错误。
y = MyValue. get();//错误!不能显式调用get访问器
MyValue. set(5);//错误!不能显式调用set访问器
代码如下:
using System; class C1 { private int m_value = 10; pubilc int Myvalue //属性不分配内存 { set { m_value = value; } get { return m_value} } } class Program { static void Main() { C1 c = new C1(); Console.WriteLine("Myvalue: {0}", c.Myvalue); c.Myvalue = 20; Console.WriteLine("Myvalue: {0}", c.Myvalue); } }
运行结果:

C#7.0为属性的getter/setter引入了另一种语法,这种语法使用表达函数体。这种语法只有在访问函数体由一个表达式组成的时候才能使用。(以后再详细介绍)
int MyValue
{
set=>value>100? 100: value;
get => theRealValue ;
}
4.7.4只读和只写属性
要想不定义属性的某个访问器,可以忽略该访问器的声明。
(1)只有get访问器的属性称为只读属性。只读属性能够安全地将一个数据项从类或类的实例中传出,而不必让调用者修改属性值。
(2)只有set访问器的属性称为只写属性。只写属性很少见,因为它们几乎没有实际用途。如果想在赋值时触发一个副作用,应该使用方法而不是属性。
(3)两个访问器中至少有一个必须定义,否则编译器会产生一条错误消息。
4.7.5属性是用来替代公有字段的方法之一
属性比公有字段更好,理由如下。
(1)属性是函数成员而不是数据成员,允许你处理输入和输出,而公有字段不行。
(2)属性可以只读或只写,而字段不行。
(3)编译后的变量和编译后的属性语义不同。
4.7.6自动属性
这里留一个坑以后再填
4.7.7静态属性
属性也可以声明为static。静态属性的访问器和所有静态成员一样,具有以下特点。
(1)不能访问类的实例成员,但能被实例成员访问。
(2)不管类是否有实例,它们都是存在的。
(3)在类的内部,可以仅使用名称来引用静态属性。
(4)在类的外部,正如前面描述的,可以通过类名或者使用using static结构来引用静态属性。
例如,下面的代码展示了一个类,它带有名为MyVa1ue的自动实现的静态属性。在Main的头三行,即使没有类的实例,也能访问属性。Main的最后一行调用一个实例方法,它从类的内部访问属性。
代码展示:
using System; using static ConsoleTestApp.Trivial; namespace ConsoleTestApp { class Trivial { public static int MyValue { get; set; } public void PrintValue() { Console.WriteLine("Value from inside:{0}", MyValue); } } class Program { static void Main() { Console.WriteLine("Init Value:{0}", Trivial.MyValue); Trivial.MyValue = 10; Console.WriteLine("New Value:{O}", Trivial.MyValue); MyValue = 20;//从类的外部访问,但由于使用了using static,所以没有使用 Console.WriteLine($"New Value:{MyValue}"); Trivial tr = new Trivial(); tr.PrintValue(); } } }

浙公网安备 33010602011771号