(1)值类型的变量本身包含他们的数据值(将存储在栈中),而引用类型的变量包含的是指向包含数据值的内存块的位置信息(将存储在受控的堆中)。
(3)引用类型共分四种类型:类、接口、数组、委派。类除了我们可以定义自己的类型外,又包括两个比较特殊的类型object和string(它们为预定义引用类型)。object是C#中所有类型(包括所有的值类型和引用类型)的根类。string类型是一个密封类型(不能被继承),其实例表示Unicode字符串;接口类型定义一系列方法的集合;委派类型是一个指向静态或实例方法的签名,类似于C/C++中的函数指针。
(1)静态变量和实例变量主要是针对类或结构内的数据成员(又叫域)而言的。静态变量在它寄存的类或结构类型被装载后得到存储空间,如果没有对它进行初始化赋值,静态变量的初始值将是它的类型所持有的缺省值。对静态变量的访问只能通过类型名,而不能通过对象名访问。
(2)实例变量在它的类实例(对象)被创建后获得存储空间,如果没有经过初始化赋值,它的初始值与静态变量的定义相同(其初始值将是它的类型所持有的缺省值)。对实例变量的访问只能通过对象名访问。
(3)传值形参、引用形参、输出参数、数组参数主要针对方法的参数类型而言的。简单地讲传值形参是对变量的值的副本的一种传递,方法内对变量的改变在方法体外不起作用。
(4)引用形参是对变量的地址的一种传递,方法内对该变量的任何改变都将在方法体外保留。无论在定义还是在使用时,都必须采用ref修饰符加以说明。
传值参数传递的是调用参数的一份拷贝,而传地址参数(引用)传递的是调用参数的内存地址,该参数在方法内外指向的是同一个存储位置。
(5)输出形参数是C#专门为有多个返回值的方法而量身定做的,它类似于引用变量,但可以在调用方法体之前不进行初始化但在被调用的方法返回前必须对该变量进行赋值,而其他的参数在进入方法体内C#都要求明确的初始化。无论在定义还是在使用时,都必须采用out修饰符。
1.2.4、C#中的操作符
C#保留了C++所有的操作符,其中指针操作符(*和->)与取地址符(&)需要有unsafe的限定。C#摈弃了范围辨析操作符(::),一律改为单点操作符(.)。下面主要介绍C#中引入的具有特殊意义的几个操作符:as,is,new,typeof,sizeof,stackalloc。
(1)as操作符用于执行兼容类型之间的转换(类似于强制类型转换),当转换失败时,as 操作符结果为null。它比常规的强制类型转换的优点在于:如果被转换的值无法转换,此时转换的结果为null,而不会产生异常。
1:using System;
2:class Person
3:{
4:}
5:public class Test
6:{ public static void Main()
7: { object you=new object();
8: Person me=new Person();
9: me =you as Person; //或 me=(Person)you 将you转换为Person对象
10: Console.WriteLine("类型:{0}",me.GetType());
11: }
12:}
(2)is操作符用于检查对象的运行时类型是否与给定类型兼容,当表达式非null且可以转化为指定类型时,is操作符结果为true,否则为false。as和is操作符是基于同样的类型鉴别和转换而设计的,两者有相似的应用场合。实际上expression as type相当于expression is type ? (type)expression :(type)null。
Point p=new Point();
if(p is Point) //返回为true
{
}
else if(p is Object) //返回为true
{
}
(3)操作符new主要用于在堆上创建对象(如创建对象、数组和代理等)和调用构造函数,值得注意的是值类型对象(例如结构)是在堆栈上创建的,而引用类型对象(例如类)是在堆上创建的。new也可用于修饰符,用于隐藏基类的成员。为隐藏继承的基类成员,使用相同名称在派生类中声明该成员并用 new修饰符重写它。
1:Point p=new Point(10,10);
2:public class MyBaseClass
3:{ public void Invoke()
4: {
5: }
6:}
7:public class MyDerived:MyBaseClass
8:{ new void Invoke() //重写以隐藏基类的成员Invoke()(实现静态多态!)
9: {
10: }
11:}
如果嵌套类型隐藏在另一种类型中,可以采用new 限定符来修改嵌套类型。
1:using System;
2:public class MyBaseC
3:{ public class MyClass //在MyBaseC类中嵌套有MyClass类
4: { public int X=200;
5: }
6:}
7:public class MyDerivedC:MyBaseC
8:{ new public class MyClass //隐藏基类中的相同的MyClass类型
9: { public int X=100;
10: }
11: public static void Main()
12: {
13: MyClass S1=new MyClass(); //使用派生类中的MyClass类
14: MyBaseC.MyClass S2=new MyBaseC.MyClass(); //强制使用基类中的MyClass类
15: Console.WriteLine(S1.X); //显示的结果为100
16: Console.WriteLine(S2.X); //显示的结果为200
17: }
18:}
(4)typeof 运算符(它不能被重载)用于获得某一类型的 System.Type 对象。
Type tVal=typeof(Point); //获得Point类的类型的System.Type 对象,从而可以使用Type类中的方法。
(5)sizeof 运算符(它不能被重载)用于获得指定的值类型(不适用于引用类型)在内存中所占用的字节数(它只能用在非安全代码中)。应用实例如下:
1:using System;
2:struct MyStruct // 定义结构类型
3:{ public int a , b;
4: public bool c;
5: void Show()
6: { Console.WriteLine("a={0} b={1} c={2}",a,b,c);
7: }
8:}
9:enum Weekdays{ Mon,Tue,Wed,Thu,Fri,Sat,Sun}; // 定义枚举类型
10:class Demo
11:{ unsafe public static void Main()
12: {
13: Console.WriteLine("sizeof(Weekdays)="+sizeof(Weekdays)); //4 bytes
14: Console.WriteLine("sizeof(MyStruct)="+sizeof(MyStruct)); //12bytes
15: Console.WriteLine("sizeof(void*)="+sizeof(void *)); //4bytes
16: }
17:}
(6)stackalloc它用来为局部指针变量分配栈内存空间(它只能用在非安全代码中)。并且无法被显示地释放,只在方法执行完后被自动释放。应用实例如下:
1:using System;
2:class Demo
3:{ unsafe public static void Main() // 非安全代码
4: { int* pArray = stackalloc int[6]; // 分配栈内存空间
5: int* p = pArray;
6: int count = 5;
7: for(;count>=0;count--)
8: { *p++=count; // 为分配的内存赋值
9: }
10: for(int i=0;i<6;i++) // 显示分配的内存内容
11: { Console.WriteLine("pArray[{0}] = {1}",i,pArray[i]);
12: }
13: } //但在方法执行完毕后将自动释放pArray[]的内存空间
14:}