变量与常量
类封装了数据与方法;类的数据表示了类的状态;类的方法表示了类的行为。
c#程序的内存类型
可以将计算机内存想象为一系列存放数据的容器,每个容器都具有一个唯一的编号,叫做内存地址。内存可以分为堆栈,托管堆,非托管堆。
堆栈 每一个进程和线程占用的是堆栈内存(进程和线程都表示必须按特定顺序执行的指令序列,进程可以看成是程序在内存中的运行实例,线程存在于进程中,是进程的一个执行单位)
每个进程和线程都有一个堆栈指针用来指示当前堆栈内存的使用情况,当堆栈内存中没有内容时,堆栈指针指向堆栈的最高地址。只有大小固定的数据类型才能使用堆栈内存来保存。
假设堆栈的最高地址为MaxStackAddress,最低地址为MinStackAddress,堆栈指针为sp。当堆栈为空时,sp=MaxStackAddress。当在堆栈中分配一个大小为s1的数据后,sp=sp-s1=MaxStackAddress-s1;当再在堆栈中分配一个大小为s2
的数据后,sp=sp-s2=MaxStackAddress-s1-s2。随着数据的不断增加,堆栈指针不断从高地址向低地址移动。
堆栈有一个很重要的特性---“后进先出”,即最后分配的数据将最先被释放。
类型
c#中类型分为值类型和引用类型,所有类型都是类。
值类型分为简单类型,枚举类型(enum)和结构类型(struct)。引用类型分为类(class),接口(interface),数组,委托(delegate),字符串string。
引用类型变量中存放的是对象的内存地址(托管堆内存),对象的值存储在这个地址指示的内存中。引用类型变量必须使用new关键字来创建。多个引用类型变量可以引用同一对象,在这种情形中,对一个变量的操作会影响另一个变量所引用的同一对象。引用类型被赋值前的值都是null。
值类型变量都存放在堆栈内存中。每个值类型变量都有自己的数据副本,所以对一个值类型变量的操作不会影响到其他变量。值类型变量的值不能为null,必须有一个确定的值.可空类型是指在值类型的基础上增加对空值null的支持,但它不是值类型,是一种复合类型(可空类型的解决思路是:把基础类型和空值null结合起来,创建新的的复合类型,复合类型的值既可以是基础类型的值,也可以是空值)可空类型的定义是在值类型的后面加?如下:
int?i; //定义可空类型变量 i=null;//变量的值为空 i=10;//变量的值为10
int i=null; //错,因为值类型变量的值不能为null
int?i=10;i++; i=null; i++;(出错,因为前面已经把i清空了) 判断可空类型是否为空if(i !=null)或
if(i.hasvalue)
当i为可空类型而且不为空时 int j=i;(错,因为i是可空类型,而j是int类型,要强制转换)int j=(int)i; int j=i??0; 表示当可空类型i不为空时,j等于i的基础类型的值,当i为空时,j=0.
转义符 /' 单引号 /" 双引号 // 反斜杠 /0 空字符 /a 感叹号 /b 退格 /f 换页 /n 换行 /r 换行 /t 水平制表符 /v 垂直制表符
常量
常量分为文本常量和符号常量 文本常量输入到程序中的值,如“10、10.5、"Mary"”等;符号常量的定义与变量的定义类似,区别是前面必须加const,常量在定义时必须初始化,定义后,符号常量的名(最好大写)和它的初始化值是等价的。如:const double PI = 3.1415926; const string CompanyName = "ABC software";
值类型的类型转换
就是将一种类型当作另一种类型来用,分为隐式转换和显式转换(强制性转换)
隐式转换
系统默认的,不需要声明,不会造成信息丢失 如:int i=10; long l=i;
显式转换
要用强制表达式转换,有时会造成信息丢失 如:int i=10;long l=i; 与 int i=10;long l=(long)i;是等价的。因此总是可以使用强制转换表达式从一种值类型转换到其他值类型.
装箱与拆箱
值类型变量与引用类型类型变量的相互转换较复杂(因为前者使用堆栈内存,后者使用托管堆内存)。从值类型转换到引用类型的过程叫装箱;从引用类型转换到值类型的过程叫拆箱.
装箱允许值类型隐式的转换为引用类型。
将一个值类型变量v装箱成一个引用类型对象o时,发生了:
(1)在托管堆创建一个对象实例o,给他分配内存。
(2)将v的值复制到对象实例o中。
(3)将o的地址压入堆栈中,此时它指向一个引用类型。
装箱实例:
using system;
class Boxing
{
public static void Main()
{
int i=10; //定义一个值类型的变量
object obj=i; //将值类型变量的值装箱到一个引用类型对象中
Console.WriteLine("值为{0},装箱对象{1}",i,obj);
i=20; //装箱后,改变值类型的值
Console.WriteLine("值为{0},装箱对象{1}",i,obj);
}
}
运行结果为:值为10,装箱对象10 值为20,装箱对象10
可以看出,值类型变量的值被拷贝到装箱得到的对象中,装箱后改变值类型的值,并不会影响到装箱对象的值。
拆箱允许引用类型显式转换为值类型
拆箱包括两个步骤:首先检查该对象实例是否是某个给定的值类型的装了箱的值,然后将值从实例中复制出来,并赋值给值类型变量。
拆箱实例:
using system;
class Unboxing
{
public static void Main()
{
int i=10; //定义一个值类型的变量
object obj=i; //将值类型变量的值装箱到一个引用类型对象中
Console.WriteLine("值为{0},装箱对象{1}",i,obj);
int j=(int)obj; //拆箱
Console.WriteLine("拆箱对象{0},值为{1}",obj,j);
}
}
运行结果为:值为10,装箱对象10 拆箱对象10,值为10
using system;
class Unboxing
{
public static void Main()
{
int i=10; //定义一个值类型的变量
object obj=i; //将值类型变量的值装箱到一个引用类型对象中
Console.WriteLine("值为{0},装箱对象{1}",i,obj);
double j=(double)obj; //拆箱
Console.WriteLine("拆箱对象{0},值为{1}",obj,j);
}
}
以上代码运行时会发生异常,以为装箱的值类型为int,而拆箱的值类型为double,装拆箱类型不一致。
数组
数组的元素类型可以是任意类型,包括数组类型。元素类型为数组的数组叫交错数组。
如: int[][] a = new int [3][]; a[0]=new int[10];a[1]=new int[5];a[2]=new int[20];
先创建一个具有3个元素的一维数组,每个元素的类型为int[],并且初始值为null,接下来给每个元素赋初始值。
可空类型的实例具有两个公共的只读属性 HasValue和Value
HasValue是一个bool类型的值,当可空类型取基础类型值时,HasValue为true,它的值可以通过Value返回。当可空类型取空值时,HasValue为false,这时不能通过Value返回它的值。
如: int? a;a=10; //a.Value为10 a.HasValue为true a=null //a.Value出错 a.HasValue为false。
类型转换总结
实现类型转换有4种方法:
1.显式转换(强制类型转换) 适合简单类型的转换 如:double i=5.12; int a=(int)i;
2.Convert类的一系列方法 如:string i="kobe123"; decimal a=Convert.ToDecimal(i);
decimal i=5.3454; double a=Convert.ToDouble(i);
注意:上面To后面要加基本类型的CTS类型。
Convert可以提供多种类型的转换,也就是Convert.*()括号中可以为很多种类型(包括string但string只能为"123"形式,而不能为"kobe123"形式).
Convert.ToInt32(null)会返回0
3.简单值类型.Parse(字符串) 如: int.Parse(string) double.Parse(string) decimal.Parse(string)等
此方法只能由字符串类型(string也只能是"123"类型)转换为简单值类型
int.Parse(null)会抛出异常,我们可以捕获异常然后再做相应的处理,比如提示用户缺少参数,而不是像Convert的方法一样把参数值当做0来处理。
4.数值.ToString() 如: int i=12345; string a=i.ToString(); double i=1234.3434 string a=i.ToString;
ToSting()方法是object类的一个静态方法,所有类都继承了这个方法。
此方法用于将数值转换为字符串。
Math类
Math类有许多方法 如:Math.Sqrt(i)平方根Math.Pow(i,5.0)5次幂Math.Log(i)自然对数Math.Sin(i)正弦