引用类型的变量与值类型的变量不同,值类型的变量存放的是值,但是引用类型的变量存放的是一个地址(它的值是一个地址),这个地址是指向一个对象的,这个对象包括类对象、数组对象、字符串对象。引用类型的变量定义之后,只是为这个变量分配了一个存放地址的空间,初始值是null,只有该变量被创建了之后,才会指向实际的对象。在引用类型的变量被创建之前,引用类型的变量是默认为null的。
对于类对象,当定义了一个类的两个引用,然后给这两个引用分别创建了两个对象,如果这两个对象的值不相同,那么两个引用的地址肯定不相同,如果这两个对象的各种值完全相同,两个引用的地址也不相同,因为这两个对象各自占用各自的不同空间;对于数组,也是跟类对象一样的;但是对于字符串,定义两个string类型的变量,给两个赋值不同,那么两个引用地址不相同,但是如果赋值相同,那么两个引用的地址是相同的,只会有一个对象而不会有两个,字符串有个字符串池的概念,与数组和类不相同。
数组是一种特殊的引用类型。数组是一些具有相同数据类型的变量的集合。这个类型可以简单类型,那么数组的每个元素就是简单类型的,默认值是0;也可以是引用类型,那么数组的每个元素都是引用类型,默认值是null。数组的下标索引是从0开始到length – 1的:
(1)、声明一个数组(只是声明了一个引用):
Type[] name ;
(2)、创建数组、初始化数组
A、int[] name = {1,2,3,4,5};
这种是声明并且创建和初始化了,数组的数据类型、长度、值就确定了。
B、int[] name = new int[5];
这种是声明并且创建,数组的数据类型、长度确定了,初始值默认为0。注意:长度5可以用一个变量代替,定义动态的数组。
C、int[] name = new int[] {1,2,3,4,5};
创建的时候,如果直接初始化了,那么数组的长度是可以省略的,那么就以初始化的为主了。
D、int[] name = new int[5] {1,2,3,4,5};
这种是声明并且创建和初始化了,数组的数据类型、长度、值就确定了。注意:这种情况下,数据的长度一定要与后面的值的个数匹配,否则就错误。
E、以上都是声明的同时,创建,也可以先声明,再创建:
int[] name;
name = {1,2,3,4,5};或者
name = new int[5];或者
name = new int[5] {1,2,3,4,5};
(3)、二维数组:
Type[,] name;
name = new int[3,4]{{1,2,3,4},{5,6,7,8},{9,10,11,12}};
在此只列出一种二维数组的创建初始化的方式,其实也可以像一维数组一样的,各种方式都适合。但是需要注意的是,二维数组也只有一对括号,不像C语言,二维数组在括号内部是用逗号隔开的,二维的是一个逗号,三维的是两个逗号。
(4)、引用数组元素
一维:name[0]:下标从零开始。
二维:name[0,0]:用的是逗号隔开而非name[0][0]。
(5)、数组的属性:
Length:数组的长度,即元素的个数。
Rank:数组的维数。
(6)、数组作函数的参数
形参:int[] name、Type[,] name
实参:name数组名
很显然,数组作为参数传递的是引用而非数组具体的值,传递之后,形参引用与实参引用就相同了,都指向了实参的对象,在函数内部形参引用所指的对象的值的的变化会直接导致实参引用所指向的对象的变化,这两引用指向的是同一个对象。
(7)、params参数
params关键字可以指定在参数数目可变处采用参数,这个就是针对函数的形参为一维的数组的时候,实参数组可以不传参数名,而直接传数目不确定的若干个值,很显然,这个适合实参数组的元素数目是不确定的情况。在方法声明中的 params关键字之后不允许任何其他参数,并且在方法声明中只允许一个 params关键字。Params只能针对一维数组。
定义一个字符串的时候,初始情况下,值为null,直到给它赋值才不为null。长度为零的字符串是:””,这个只是长度为零,而非null。下面重点介绍一下字符串中常用的函数:
str1.CompareTo(str2)
这个是字符串比较函数,将str1与str2进行比较,返回一个整数值。如果str1>str2,那么返回整数1,如果str1=str2,那么返回整数0,如果str1<str2,那么返回整数-1.这个字符串之间的比较其实就是按照C语言里面字符串比较的原理来比较的。
A、public staticint Compare (string strA , string strB)
这个是比较strA – strB,返回正负1或者0。
B、public staticint Compare (string strA, string strB,bool ignoreCase)
这个是比较strA – strB,是否忽略大小写了。
C、public staticint Compare (string strA, int indexA,string strB,int indexB,int length)
这个是比较strA – strB,indexA、indexB是字符串中字符的起始位置,索引是从0开始的,lenngth是比较的字符串长度。
D、public staticint Compare (string strA, int indexA,string strB,int indexB,int length,bool ignoreCase)
这个在函数C的基础上添加了是否忽略大小写的选项。
public static int CompareOrdinal (string strA,string strB)
public static int CompareOrdinal (string strA,int indexA,string strB,int indexB,int length)
以上三个函数都是比较字符串的函数,默认按照C语言里面字符串比较的原理来比较的。
public bool Contains (string value)
如果 value参数出现在此字符串中,或者 value 为空字符串 (""),则为 true;否则为 false。
将一个浮点数值字符串转换成为想要的格式,比如保留几位小数,可以使用math.round函数。
C#格式化数值结果表:
字符 |
说明 |
示例 |
输出 |
C |
货币 |
string.Format("{0:C3}", 2) |
$2.000 |
D |
十进制 |
string.Format("{0:D3}", 2) |
002 |
E |
科学计数法 |
1.20E+001 |
1.20E+001 |
G |
常规 |
string.Format("{0:G}", 2) |
2 |
N |
用分号隔开的数字 |
string.Format("{0:N}", 250000) |
250,000.00 |
X |
十六进制 |
string.Format("{0:X000}", 12) |
C |
|
|
string.Format("{0:000.000}", 12.2) |
012.200 |
A、publicint IndexOf (char value)
如果找到该字符,则为 value的索引位置;否则如果未找到,则为 -1。索引是从0开始的。
B、publicint IndexOf (string value)
如果找到该字符串,则为 value的索引位置;如果未找到该字符,则为 -1。如果 value为长度为0的字符串,则返回值为 0。
C、publicint IndexOf (char value,int startIndex)
搜索字符,startIndex是搜索的起始位置,字符串索引是从0开始的。
D、publicint IndexOf (string value,int startIndex)
搜索字符串,startIndex是搜索的起始位置,字符串索引是从0开始的。如果 value为长度为0的字符串则返回值为 startIndex。
E、publicint IndexOf (char value,int startIndex,int count)
搜索从 startIndex开始,一直搜索到 startIndex+count-1。位于 startIndex+count的字符不包含在搜索范围内,搜索范围是从startIndex 开始到startIndex+count-1结束。索引编号从零开始。
F、publicint IndexOf (string value,int startIndex,int count)
搜索从 startIndex开始,一直搜索到 startIndex+count-1。位于 startIndex+count的字符不包含在搜索范围内,搜索范围是从startIndex 开始到startIndex+count-1结束。索引编号从零开始。
以上的搜索都是搜索value第一次出现的索引,以上的索引指的是字符的索引而非字节的索引。以上搜索都是区分大小写的。
A、publicint IndexOfAny (char[] anyOf)
求出anyof中的任何一个字符第一次在母字符串中出现的字符位置。最后求出最靠前的第一次出现的位置。
B、publicint IndexOfAny (char[] anyOf, int startIndex)
C、publicint IndexOfAny (char[] anyOf, int startIndex,int count)
注意:以上几个函数都是字符数组,只能传递字符数组。
public string Insert (int startIndex,string value)
在索引startIndex之前插入value.
public static bool IsNullOrEmpty (string value)
判断字符串value是否为null或者长度为零的字符串,字符串中长度为0的字符串不是null,没有被创建的才是null。
以上两个函数指的是找出最后一次出现的索引。
求出一个字符串所含有的字符的个数,求长度的时候,字符串后面没有一个空字符作为字符串的结束标志。比如:“张wj”.length = 3。
public string PadLeft (int totalWidth)
public string PadLeft (int totalWidth,char paddingChar)
右对齐此实例中的字符,在左边用paddingChar填充以达到指定的总长度。如果 totalWidth小于此实例的长度,则为与此实例相同的新 String。第一个函数是用空格填充。
public string PadRight (int totalWidth)
public string PadRight (int totalWidth,char paddingChar)
左对齐此实例中的字符,在右边用paddingChar填充以达到指定的总长度。如果 totalWidth小于此实例的长度,则为与此实例相同的新 String。第一个函数是用空格填充。
public string Remove (int startIndex)
public string Remove (int startIndex,int count)
从此实例中删除指定个数的字符。startIndex开始删除字符的位置。 count 要删除的字符数。
public string Replace (char oldChar,char newChar)
oldChar 要替换的 Unicode字符。 newChar 要替换 oldChar的所有匹配项的 Unicode 字符。源字符串没有变化。
public string Replace ( string oldValue,string newValue)
oldValue 要替换的String。 newValue要替换 oldValue 的所有匹配项的 String。源字符串没有变化。
public string ToLower ()
public string ToUpper ()
将字符串转换成大小写返回。
public string[] Split (params char[] separator)
返回包含在此实例中的子字符串(由指定Char 数组的元素分隔)的String 数组。
public string Substring ( int startIndex)
注意:startIndex必须是0--------string.length这个范围,当为string.length的时候,返回的是长度为0的字符串。
public string Substring ( int startIndex,int length)
注意:startIndex必须是0---------string.length这个范围,如果为string.length,length就必须为0,此时返回的是长度为0的字符串。startIndex加 length 之和大于string.length或 length小于零都会报错。
public string Trim ()
消除前后的空格
DateTime dti = new DateTime(int year,int month,int Day)
上面这个构造函数只有年月日,没有小时分钟秒,那么小时分钟秒是默认为0的。
DateTime dti = new DateTime(int year,int month,int Day,int hour,int minute,int second)
Date:获取当前DateTime对象的日期部分。时间部分默认为0.返回DateTime类型。
TimeOfDay:获取当前DateTime对象的时间部分,以TimeSpan类型返回。
Year:获取当前DateTime对象的年部分,返回int类型。
Month:获取当前DateTime对象的月部分,返回int类型。
Day:获取当前DateTime对象的日期是该月的第几天,即几号,返回int类型。
Hour:获取当前DateTime对象的小时部分,返回int类型。
Minute:获取当前DateTime对象的分钟部分,返回int类型。
Second:获取当前DateTime对象的秒部分,返回int类型。
DayOfWeek:表示星期几,返回的是枚举类型DayOfWeek的值。
DayOfYear:表示该年中的第几天,返回int类型。
DateTime.Now:返回当前计算机的时间日期,返回的是DateTime类型。
DateTime.Today:返回当前计算机的日期,时间默认为0,返回的是DateTime类型。
AddYears、AddMonths、AddDays、AddHours、AddMinutes、AddSeconds
可以对源对象添加年、月、日、小时、分钟、秒,然后以DateTime类型返回,源对象的值并没有改变。
int DateTime.DaysInMonth(int year,int month)
这个是求出指定的年、月中的天数。
DateTime dti = DateTime.Parse("2009-8-7 2:12:12");
上面这个函数是将时间日期字符串转换成为DateTime类型,如果字符串时间省略了,那么时间默认为0返回;如果日期省略了,那么就把当前计算机的日期与字符串时间一起返回。要注意字符串的格式,能够让.NET编译器识别。
dti.ToString("yyyy-MM-dd hh-mm-ss")
上面这个函数是将DateTime类型转换成为时间日期字符串,按照格式:yyyy表示四位的年份,大写MM表示两位的月份,dd表示两位的日,hh表示12小时制两位的小时(HH表示的是24小时制的小时),小写mm表示两位的分钟,ss表示两位的秒。中间的间隔符号‘-’是任意的,可以是中文。
IList接口有两个实现类,这两个类是集合类型,其中一个是ArrayList,这个集合存在于命名空间System.Collection中;另外一个是List,这个集合存在于命名空间System.Collection.Generic中。
ArrayList是容量不固定的,可以随时扩展的一个集合类型。它是一维的,可以存放任何的数据类型,不需要数据类型完全相同。
定义ArrayList对象:
ArrayList al = new ArrayList();
Ilist al = new ArrayList();
这种定义是用接口的引用指向实现类的对象,那么此时接口的引用只能调用在接口中声明过的在实现类中定义好的成员。下面这些属性和方法在接口中都声明过。
属性:
Count:表示集合中的实际成员的个数:al. Count
方法:
Add方法:Add(object value)这个是往集合中添加元素,每次添加都是往最后一个元素之后添加的,不会往中间插入: al.Add(“text”)、 al.Add(5.2)、 al.Add(new student())。
Insert方法:Insert(int index,object value),这个方法是往某个指定的索引位置上添加一个值。其中index范围是:0~~~ al. Count,超出范围就会报错;value值可以是任何的类型。插入之后,原来位置的数据自动往下移动:al. Insert (5,“text”)。
Remove方法:Remove(object value),这个是移除某一项,根据值来移除的,移除之后原来的位置被后面的值填充。对于这个函数,因为value是object类型的,所以有些是可以移除的,比如字符串,整数,但是对于浮点数是无法移除的,因为浮点数无法比较。所以这个函数用的比较少:al. Remove(“士大夫”)。
RemoveAt方法:RemoveAt(int index),这个函数可以准确的移除某一项,因为它是根据索引来移除的,其中index范围是:0~~~ al. Count - 1,超出范围就会报错:al.RemoveAt(5)
Clear方法:Clear(),这个方法是将集合清空,让count为0.没参数:al. Clear()。
访问集合中的元素:集合对象[intindex]
其中index范围是:0~~~ al. Count - 1,超出范围就会报错,这个值是object类型的,可以读写的:al[5]
可以用foreach遍历:
Foreach(string value in al){console.writeline(value)},这种集合元素全部是字符串类型的。
Foreach(object value in al){console.writeline(value)},这种集合是混合类型。
List是容量不固定的,可以随时扩展的一个集合类型。它是一维的。但是这个是泛型,即固定了数据类型的,这个集合中的数据类型必须是一致的,但是类型是任意的。泛型List<string>与ArrayList是一样的使用,函数和属性没什么区别,只是泛型一定要指定类型。
IList<string> al =new List<string>();--正确,泛型接口
List<string> al =new List<string>();--正确,泛型
IList al = newList<string>();--错误
List al = newList<string>();--错误
IDictionary接口有四个实现类,这四个类是集合类型,其中Hashtable、SortedList这两个集合存在于命名空间System.Collection中,是非泛型的;另外Dictionary、SortedList这两个集合存在于命名空间System.Collection.Generic中,是泛型的。
Hashtable是一个用来存放键、值对集合的数据结构,它的容量是不固定的,可以随时扩充。它可以存放任何类型的键、值。它里面的数据是无序的散列码。添加的时候无序,查询的时候会困难,很慢。
定义一个Hashtable对象:
Hashtable ht = new Hashtable();
IDictionary ht = new Hashtable();
属性:
Count:表示集合元素的个数。
Keys:键的集合。
Values:值的集合。
方法:
Add(键、值):添加元素的,不是一个个往后添加的,是散列的。
Remove(键):移除元素的。
Clear():清空元素的。
因为无序,所以不可能存在Insert和RemoveAt方法。
访问元素:
Hashtable是无序的散列码,所以对它的访问是不能通过索引的,因为它没有索引,对它的访问是通过键来取值的,所以在整个集合中,键是绝对不能重复的。
访问如下:ht [键],可以对其进行读写,是object类型的。
可以用foreach遍历:
Foreach(string value in ht.keys){console.writeline(ht[value])},这种集合元素全部是字符串类型的。
Foreach(object value in ht.keys){console.writeline(ht[value])},这种集合是混合类型。
SortedList是按照键进行排序的键值对的集合。添加的时候会按照键来排序,添加的时候慢,查询的时候会很快。因为是按照键进行排序,所以键必须能够排序,所以要么为全部为字符串,要么全部为数值。因为有序,所以存在整数索引。
定义一个SortedList对象:
SortedList sl = new Hashtable();
IDictionary sl = new Hashtable();接口中没有RemoveAt方法。
属性:
Count:表示集合元素的个数。
Keys:键的集合。
Values:值的集合。
方法:
Add(键、值):添加元素的,不是一个个往后添加的,是排序的。
Remove(键):移除元素的。
RemoveAt(intindex):根据索引来移除,index范围是:0~~~ sl. Count - 1
Clear():清空元素的。
虽然有索引,但是仍然没有Insert方法。
访问元素:
SortedList虽然是有序的,但是对它的访问是不能通过索引的,对它的访问还是要通过键来取值的,所以在整个集合中,键是绝对不能重复的。
访问如下:sl [键],可以对其进行读写,是object类型的。
可以用foreach遍历:
Foreach(string value in sl.keys){console.writeline(sl [value])},这种集合元素全部是字符串类型的。
Foreach(object value in sl.keys){console.writeline(sl [value])},这种集合是混合类型。
这种遍历会按照排好的顺序来遍历。
这个跟Hashtable基本一样,属性、函数都一样,也是无序散列码,只是它能够规定键、值的类型。
Dictionary<string,int> d = new Dictionary<string, int>();
IDictionary<string,int> d = new Dictionary<string, int>();
这个与上面的非泛型的SortedList也基本一样,有相同的函数和属性。只是它能够规定键、值的类型。
SortedList<string,int> d = new SortedList<string, int>();
IDictionary<string,int> d = new SortedList<string, int>();--接口中没有RemoveAt方法。
注意:非泛型的是以前的数据结构,这种是非常不规范的,因为在大多数情况下,我们使用的数据类型都是一致的,所以以后使用的时候都统一使用泛型结构。这样能保证数据的类型统一和程序的准确。对于二维数据,如果插入特别平凡,但是查询不平凡,一般就使用哈希表,反之如果插入不是很平凡,但是查询非常平凡,就使用SortedList。
如果是在函数内部定义的引用类型变量,那么它的作用域从定义开始到函数结束为止。生存期也是这样。该引用所创建的对象的作用域是被指向该对象的引用所控制的,因为一个对象可以先被某个引用所指,再被另外一个引用所指,那么当前它被哪个引用所指,那么作用域就与该引用相同,生存期也随着当前指向它的引用的变化而变化,但是一旦没有任何引用指向该对象了,该对象就没有作用域了,但是生存期不一定会马上结束,因为没有显示的去回收和释放资源,而是由C#自动的垃圾回收机制去处理,资源不一定会马上释放,所以生存期可能还存在。
如果是在函数外面类的内部定义的引用类型的变量,那么它的作用域就是全局的,能被类中的所有函数调用,生存期是从类对象创建开始到对象释放为止。该引用所指向的对象的作用域与该引用的作用域一致,因为外界使用对象其实就是通过该引用来实现的,最终该引用所指向的对象没有任何引用来指向该对象了,该对象就没有作用域了,但是生存期不一定会马上结束,因为没有显示的去回收和释放资源,而是由C#自动的垃圾回收机制去处理,资源不一定会马上释放,所以生存期可能还存在。
总结:函数里面定义的引用具有函数内定义开始到函数结束的作用域;函数外定义的引用具有整个类内部的作用域,所有函数都可以调用。对于引用所指向的具体的对象,一旦没有任何引用指向该对象了,该对象就没有作用域了,但是生存期不一定会马上结束,因为没有显示的去回收和释放资源,而是由C#自动的垃圾回收机制去处理,回收机制不一定马上就启动,所以资源不一定会马上释放,所以生存期可能还存在。
2009-02-12----2009-02-14