如果需要使用同一类型的多个对象,就可以使用集合和数组,c#使用特殊句号声明和初始化数组,简单来说需要时使用同一类型的多个对象时,就可以使用数组,数组是一种数据结构。
数组的声明:
int[] Array;
数组的初始化:
声明数组后必须给数组分配内存,以保存数组的所有元素,数组是引用类型,所以必须给他分配堆上内存,因此使用new运算符。 数组声明的的方式。
int[] Array=new int[];
初始化的三种方式:
int[] Array=new int[4]{1,2,3,4};
int[] Array=new int[]{1,2,3,4};
int[] Array={1,2,3,4};
在声明和初始化数组后就可以使用索引器访问数组的元素了,数组只支持有整型参数的索引器,通过索引便可以访问其中的元素(从0开始)。
int[] Array={1,2,3,4};
Array[0]=1, Array[3]=4;
如果不知道数组的元素个数可以用Length属性,下面两种也是取数据的方式
for(int i=0;i<Array.length;i++)
{
int a=Array[i];
}
foreach(int b in Array)
{
int a=b;
}
引用类型数组
除了能声明预定义类型的数组外,还可以声明自定义类型数组
public class Person
{
public string FirstName;
public string LastName;
}
数组声明:
person[] Array=new person[2];
数组初始化::
和int类型一样。
person[] Array=new person[2]{new person{FirstName="大卫",LastName="菠萝"},new person{FirstName="小卫",LastName=“土豆”}};
其实引用类型的数组和int类型数组一样,只不过把类型换了一下而已。
多维数组
一般数组(一维数组)用一个整数来索引,多维用两个或者多个整数来索引。
二维数组声明
int[,] Array=new int[2,3](代表2行3列的数组)。
二维数组初始化
int[,] Array=new int[]{{1,2},{1,3},{1,4}}//(代表3行2列的数组)。
//取值,索引从0开始
Array[0,0]=1;
Array[0,1]=2;
3维数组及以上,还有锯齿数组都差不多,就不讨论了。
Array类
用方括号声明数组是c#中使用Array类的表示法,在后台使用c#语法,会创建一个派生自抽象基类Array的新类,这样就可以使用Array为每个c#数组定义的方法和属性了,,例如前面使用的Length属性,或者是foreach语句来迭代数组,其实使用了Array类中的GetEnumerator()方法。(我的理解就是数组可以使用Array类中的属性和方法).
Array类实现的其他属性有longlength和rank,longlength表示所有维数中元素的个数,rank表示维数。
Array类是抽象类,所以不能构造函数来创造数组,但是可以用静态方法来CreateInstance()方法来创建数组,如果事先不知道元素类型就很有用,因为类型可以当做参数传进去。
//创建一个类型为int,大小为5的数组
Array IntArray=Array.CreateInstance(typeof(int),5);
//赋值
for(int i=0;i<IntArray.length;i++)
{
IntArray.SetValue(33,i);//后面i为索引
}
//取值
for(int i=0;i<IntArray.length;i++)
{
int a= IntArray.GetValue(i);
}
引用数组,锯齿数据,多维数组同样可以用Array.CrueateInstance方法来创建,则不再讨论。
复制数组
因为数组是引用类型,所以将一个数组赋值为另外一个数组,就会等到两个引用同一数组的变量,复制数组会实现ICloneable接口,这个接口定义的Clone()方法会创建数组的浅表副本(我的理解就是 数组 a=数组 b 改变数组a的值,b也会跟着改变,数组 a=数组b.clone()改变a的值不会改变b的值)
排序
Array类使用QuickSort算法对数组中的元素进行排序,Sort()方法需要数组中元素实现Icomparable接口
int[] Array={3,2,1};
Array.sort(Array);
//从小到大排序,则Array里数据排序
Array[0]=1;
Array[1]=2;
Array[2]=2;
引用类型数组排序就不在这里介绍了,没有封装好的方法,需要自己写。
数组作为参数
int[] Array={1,2,3};
static void TestArray(int[] pram)
{
//....... 函数体
}
//数组协边,即数组也可以声明为基类(通俗点就是object[] 可以传数组)
static void TestArray(object[] pram)//可以传引用类型的数组
{
//....... 函数体
}
数组协变,只能用于引用类型,不能用于值类型,数组协边有个问题,他只能通过运行时异常来解决,如果把引用数组赋予object[]数组,object数组就可以使用使用派生自object的任何元素。(不建议用object[])。
ArraySegment<T>
结构ArraySegment<T>表示数组的一段,如果需要使用不同的方法处理某个大型方法的不同部分,则需要将相应的部分传到相应的方法中,更有效的是使用一个数组,将整个数组传递到不同方法去。
//举个简单的例子,若有两个不同的数组,选取不同的部分求和,则可以使用Arraysegment
static int SumOfSegment(Arrsegement<int>[] segments)
{
int sum=0;
foreach(var segment in segments)
{
for(int=segment.offest;i<segment.offset+segment.count;i++)
{
sum+=segment.array[i];
}
}
return sum;
}
int[] a={1,2,3,4,5};
int[] b={2,3,4,5,6,7};
//数组a取出索引1,往后数两个数的数(从索引开始算),数组b,取出索引1,往后数3个数的数(从1开始算),a 取出2,3,b取出3,4,5
static void TestSegMent()
{
ArraySegment<int>[] segments=new ArraySegment<int>[2]{new ArraySegment<int>(a,1,2),new ArraySegment<int>(b,1,3)};//将不同数组的不同部分传入segment中(自我感觉不咋用的到0.0)
int sum=SumOfSegment(segments);
}
枚举
在foreach语句中使用枚举,可以迭代集合中元素,无须知道集合的个数,foreach使用了一个枚举器。;数组或集合实现带GetEumerator()方法的IEnumerable接口。
Tip:GetEnumerator()方法用IEnumerable接口定义,foreach语句并不真的需要在集合类中实现这个接口,有一个名为GetEnumerator的方法,他返回了实现IEnumerator接口的对象就足够了。
IEnumerator接口
foreach语句使用IEnumerator接口的方法和属性,迭代集合中所有的元素,为此IEnumerator定义了current属性,来返回光标当前所在的元素。该接口的MoveNext()方法移动到集合的下一个元素,如果有这个元素就返回true,如果没有下一个元素则返回false.该接口的泛型版本IEnumerator<T> 接口派生自IDisposable接口,因此定义了Dispose()方法,来清理枚举器产生的资源。
Foreach语句
int[] array={1,2,3,4};
foreach(int a in array)
{
console,writeline(a)
}
//上面的foreach等价于下面的枚举器
IEnumeator<int> enumerator=array.GetEnumerator()//用getenumerator()方法获得数组的一个枚举器
while(enumerator.movenext())
{
int p=enumerator.current;
console.writeline(p);
}
Yield语句
c#2.0添加了yield语句,以便于创建枚举器,yield return语句返回集合的一个元素,并移动到下一个元素上,yield back可以停止迭代。
//返回hello world
pubic IEnumerator<string> GetEnumerator()
{
yield return "Hello";
yield return "wrold";
}
tip:包含yeild语句的方法和属性也被成为迭代块,迭代块必须声明为返回IEnumerator或者IEnumerable接口,或者这些接口的泛型版本。这个快可以包含多个yeild return和yeild back语句,但是不能包含return语句.
元组
元组的初始化
//元组初始化时应设值否则会报错
Tuple<int,string> tuple=new Tuple<int,string>(1,"2");
//或者下一种
Tuple<int,string> tuple=new Tuple<int,string>(1,"2");
数组是和并相同类型的成员,元组是合并不同类型的成员。,net定义了8个泛型的Tuple类和一个静态Tuple类,例如Tuple<T1>包含一个元素,Tuple<T1,T2>包含了两个元素。
public Static Tuple<int,string> Divide(int a,int b)
{
int result1=a+b;
int result=(a-b).tostring();
return Tuple.Create<int,int>(result1,reult2);
}
public static Test()
{
Tuple<int,string> tuple= Divide();
int a=tuple.item1;//第一个数
string b=tuple.item2;//第二个数
}
Tip:如果元祖包含的项超过8个,就可以用带8个参数的Tuple类定义,最后一个模板参数是TRest表示必须给它传递一个元组,举个例子
//当元组包含的项超过8个时,最后一个模板必须是元组
var tuple = new Tuple<int, int, int, int, int, int, int, Tuple<int, string>>(1, 1, 1, 1, 1, 1, 1, Tuple.Create<int, string>(1, "2"));
//或者下一种
var tuple2 = new Tuple<int, int, int, int, int, int, int, Tuple<int, string>>(1, 1, 1, 1, 1, 1, 1, new Tuple<int, string>(1,"2"));
(自我感觉元组的使用就是当类中的元素少的时候,可以用元组替代,简化代码)。