同一类型和不同类型的多个对象

使用同一类型的多个对象,使用集合和数组。

使用不同类型的多个对象,使用Tuple(元组)。

初始化数组

int[] myArray = new int[];

myArray 存放在栈中,而 myArray 的内容 放在 托管堆。

声明数组后,必须为数组分配内存,以保存数组的所有的元素。数组是引用类型,必须给它分配堆上的内存。

如果不知道数组包括多少元素,可以使用集合。

还可以用数组初始化器。

int[] myArray = new int[]{,,,};

访问数组

myArray[] = ;
myArray[] = ;

如果使用错误的索引值,会抛出 IndexOutOfRangeException 错误。

遍历数组

int[] myArray = new int[]{,,,};
for (int i = ; i < myArray.Length; i++)
{
Console.WriteLine("{0}",myArray[i]);
}
int[] myArray = new int[]{,,,};
foreach (int val in myArray)
{
Console.WriteLine("{0}",val);
}

foreach 语句利用了本章 IEnumerable 和 IEnumerator 接口。

使用引用类型

Person[] myPersons = new Person[];
myPersons[] = new Person() {FirstName = "FirstName1", LastName = "LastName1"};
myPersons[] = new Person() { FirstName = "FirstName2", LastName = "LastName2" };
Person[] myPersons =
{
new Person {FirstName = "FirstName1", LastName = "LastName1"},
new Person {FirstName = "FirstName2", LastName = "LastName2"}
};

多维数组

int[,] mInts = new int[,];
mInts[, ] = ;
mInts[, ] = ;
mInts[, ] = ;
mInts[, ] = ;
int[,] mInts =
{
{, },
{, },
{, },
{, }
};

当然还可以声明三维数组

int[,,] mInts = new int[,,];
mInts[, , ] = ;
mInts[, , ] = ;
mInts[, , ] = ;
mInts[, , ] = ;
mInts[, , ] = ;
mInts[, , ] = ;
mInts[, , ] = ;
mInts[, , ] = ;
int[,,] mInts =
{
{{, }, {, }},
{{, }, {, }},
{{, }, {, }}
};

锯齿数组

int[][] jagged = new int[][];

在初始化锯齿数组是,只在第1对方括号中设置该数组包含的行数。定义各行中元素个数的第2个方括号设置为空,让数组每行包含不同元素个数,之后指定行中元素个数。

int[][] jagged = new int[][];
jagged[] = new int[] {, };
jagged[] = new int[] {, , };
jagged[] = new int[] {, , , };

Array类

方括号声明数组, 实际上派生一个自抽象基类Array新类。foreach语句迭代数组,实际就是调用 Array中的 GetEnumerator()。

Array.LongLength 包含数组的元素个数超出了整数的取值范围,就可以使用LongLength属性来获得元素的个数。

Array.Rank 获得数组的维数。

创建数组

Array intArray1 = Array.CreateInstance(typeof(int),);
for (int i = ; i < ; i++)
{
intArray1.SetValue( + i,i);
} for (int i = ; i < ; i++)
{
Console.WriteLine(intArray1.GetValue(i));
} int[] intArray2 = (int[]) intArray1;

创建多维数组

int[] lengths = {, };
int[] lowerBounds = {, };
Array racers = Array.CreateInstance(typeof(Person),lengths,lowerBounds);

复制数组

数组实现ICloneable接口,然后调用Clone返回浅副本。

int[] intArray1 = {, , };
int[] intArray2 = (int[])intArray1.Clone();

copy必须传递足够元素的数组。

有时也需要深度克隆,但克隆的时候,要仔细思考一下,是否真的需要克隆。

排序

int[] intArray1 = {, , };
Array.Sort(intArray1);
foreach (var i in intArray1)
{
Console.WriteLine(i);
}

如果数组是自定义类,那么类就要实现Icomparable接口

public class Person: IComparable<Person>
{ public string FirstName { get; set; }
public string LastName { get; set; } public int CompareTo(Person other)
{
if (other == null) return ;
int result = String.CompareOrdinal(this.LastName, other.LastName);
if (result == )
{
result = String.CompareOrdinal(this.FirstName, other.FirstName);
}
return result;
} public override string ToString()
{
return String.Format("{0} {1}",FirstName,LastName);
}
}

对象相等,方法返回0。小于 返回 小于0的值 ,大于返回 大于0的值。

如果不能修改类,还可以新类里 实现 IComparer 或 IComparer<T> 实现接口。

public enum PersonCompareType
{
FirstName,
LastName
} public class PersonComparer : IComparer<Person>
{
private PersonCompareType compareType; public PersonComparer(PersonCompareType compareType)
{
this.compareType = compareType;
} #region IComparer<Person> Members public int Compare(Person x, Person y)
{
if (x == null) throw new ArgumentNullException("x");
if (y == null) throw new ArgumentNullException("y"); switch (compareType)
{
case PersonCompareType.FirstName:
return String.Compare(x.FirstName, y.FirstName, StringComparison.Ordinal);
case PersonCompareType.LastName:
return String.Compare(x.LastName, y.LastName, StringComparison.Ordinal);
default:
throw new ArgumentException(
"unexpected compare type");
}
} #endregion
}
Array.Sort(persons,
new PersonComparer(PersonCompareType.FirstName)); foreach (Person p in persons)
{
Console.WriteLine(p);
}

数组协变

数值支持协变。这表示数组可以声明为基类,其派生类型的元素可以赋予数组元组。

static void TestArray(object[] objects)

这里就可以传入 Person[] 参数进去了。

注意,数组协变只能用于引用类型,不能用于值类型。另外如果object[],被赋予了 Person[] 。就不能赋值其他类型的值了,否则运行时,会出现 ArrayTypeMismatchException 的异常。

ArraySegment<T>

ArraySegment表示数组的一部分。

static void Main(string[] args)
{
int[] ar1 = {, , , , , , };
int[] ar2 = { , , , , , , }; ArraySegment<int>[] setmentInts = new ArraySegment<int>[]
{
new ArraySegment<int>(ar1,,),
new ArraySegment<int>(ar2,,),
}; int sum = SumOfSegments(setmentInts);
Console.WriteLine(sum);
} static int SumOfSegments(ArraySegment<int>[] segments)
{
int sum = ;
foreach (var segment in segments)
{
//for (int i = segment.Offset; i < segment.Offset + segment.Count; i++)
//{
// sum += segment.Array[i];
//} foreach (var value in segment)
{
sum += value;
}
}
return sum;
}

数组段不复制原数组的元素,但原数组可以通过ArraySegment<T>访问。如果数组段的元素改变了,这些变换就会反映到原数组中。

枚举

数组或集合实现带 GetEumerator方法的IEumerable 接口。 GetEumberator 方法返回一个实现Ieumerable 接口的枚举。然后 foreach语句就可以使用Ieumerable接口迭代集合。

IEnumerator接口

foreach使用IEnumerator接口的方法和属性,迭代集合中的所有方法。为此,IEnumerator定义了Current属性,来返回光标所在的元素,该接口的MoveNext()方法移动到集合的下一个元素上,如果有这个元素,该方法就返回true。如果集合不再有更多的元素,该方法返回false。

这个接口的泛型版本IEnumerator<T> 派生字接口 IDispose ,因此定义了 Dispose 方法,来清空枚举器占用的资源。

IEnumerator 接口还定义了 Reset() 方法,以与 COM 交互操作。

foreach语句

C#的 foreach 语句 不会解析为 IL代码中的 foreach语句。 C#编译器会把 foreach语句转换为 IEnumerator接口的方法和属性。

foreach (var value in ar1)
{
Console.WriteLine(value);
}

解析为

int[] ar1 = {, , , , , , };
int[] ar2 = { , , , , , , }; IEnumerator enumerator = ar1.GetEnumerator();
while (enumerator.MoveNext())
{
Console.WriteLine(enumerator.Current);
}

yield

yield可以创建枚举器,yield return语句返回集合一个元素,并移动到下一个元素上。yield break 可停止迭代。

public class SimpleConllection : IEnumerable<string>
{
public IEnumerator<string> GetEnumerator()
{
yield return "Hello";
yield return "World";
} IEnumerator IEnumerable.GetEnumerator()
{
return GetEnumerator();
}
} static void Main(string[] args)
{
SimpleConllection simpleConllection = new SimpleConllection();
foreach (string s in simpleConllection)
{
Console.WriteLine(s);
}
}

包含yield语句的方法或属性称为迭代快,迭代块必须声明返回IEnumerator 和 IEnumerable 接口,或者这些接口的泛型版本。这个块可以包含多条 yield return 语句 或 yield break 语句。但不能包含 return 语句。

使用迭代块,编译器会生成 yield 类型,其中包含一个状态机,代码如下

public class SimpleConllection
{
public IEnumerator GetEnumerator()
{
return new Enumerator();
} public class Enumerator : IEnumerator<string>, IEnumerator, IDisposable
{
private int state;
private string current; public Enumerator(int state)
{
this.state = state;
} bool System.Collections.IEnumerator.MoveNext()
{
switch (state)
{
case :
current = "Hello";
state = ;
return true;
case :
current = "World";
state = ;
return true;
case :
break;
}
return false;
} public void Dispose()
{ } public void Reset()
{ } public string Current { get; private set; } object IEnumerator.Current
{
get { return current; }
}
}
}

yield 语句 会生成一个枚举器,而不仅仅生成一个包含的项的列表。这个枚举器通过 foreach 语句调用。foreach中访问每一项是,就会访问枚举器。这样迭代大数据时,无须一次把所有的数据读入内存。

元组

数组存储相同类型的对象,元组存放不同类型的对象。.net 4.0 中 定义了 8个泛型Tuple类和一个静态Tuple类。用于创建Tuple。

http://blog.csdn.net/limlimlim/article/details/7835926

private static Tuple<int, int> Divide(int dividend, int divisor)
{
return Tuple.Create<int, int>(dividend, divisor);
} static void Main(string[] args)
{
Tuple<int, int> result = Divide(, );
Console.WriteLine("result of divison:{0}," +
"reminder:{1}", result.Item1, result.Item2);
}

当然 元组 还可以套用 元组。

http://blog.csdn.net/limlimlim/article/details/7835926

数组和元组 都实现了 IStructuralComparable,IStructuralEquatable 接口。

IStructuralEquatable 用于比较两个元组或数组是否有相同的内容。

IStructuralEquatable 用于元组或数组排序。

Tuple 也提供了 Equals

http://www.tuicool.com/articles/iqMv2i

C# 数组(5) 持续更新的更多相关文章

  1. 学习Swift -- 数组(Array) - 持续更新

    集合类型--数组 Array是Swift中的一种集合类型:数组,数组是使用有序列表储存同一类型的多个值,与OC的NSArray的最大不同是,Swift的数组是值类型,OC的数组是引用类型 声明数组的方 ...

  2. PHP开发过程中数组汇总 [ 持续更新系列 ]

    开发过程中经常会使用到数组函数,故特地总结出来,自己熟悉,同时供大家参考!(实例部分会抽空尽快完成) 一.目录 array_merge(); 合并数组 array_keys(); array_filt ...

  3. 前端深入之js篇丨Array数组操作从入门到成神Up Up Up,持续更新中

    写在前面 随着前端深入的不断学习,发现数组这个数据结构在前端中有着相当大的存在感,由于我初学前端的时候并没有系统性的学习数组,所以我将通过这篇文章同你一起学习数组,希望我们能一起进步,学会熟练操作数组 ...

  4. iOS开发系列文章(持续更新……)

    iOS开发系列的文章,内容循序渐进,包含C语言.ObjC.iOS开发以及日后要写的游戏开发和Swift编程几部分内容.文章会持续更新,希望大家多多关注,如果文章对你有帮助请点赞支持,多谢! 为了方便大 ...

  5. 总结js常用函数和常用技巧(持续更新)

    学习和工作的过程中总结的干货,包括常用函数.常用js技巧.常用正则表达式.git笔记等.为刚接触前端的童鞋们提供一个简单的查询的途径,也以此来缅怀我的前端学习之路. PS:此文档,我会持续更新. Aj ...

  6. ( 译、持续更新 ) JavaScript 上分小技巧(四)

    后续如有内容,本篇将会照常更新并排满15个知识点,以下是其他几篇译文的地址: 第一篇地址:( 译.持续更新 ) JavaScript 上分小技巧(一) 第二篇地址:( 译.持续更新 ) JavaScr ...

  7. ( 译、持续更新 ) JavaScript 上分小技巧(三)

    最近家里杂事较多,自学时间实在少的可怜,所以都在空闲时间看看老外写的内容,学习之外顺便翻译分享~等学习的时间充足些再写写自己的一些学习内容和知识点分析(最近有在接触的:复习(C#,SQL).(学习)T ...

  8. ( 译、持续更新 ) JavaScript 上分小技巧(二)

    考虑到文章过长,不便于阅读,这里分出第二篇,如有后续,每15个知识点分为一篇... 第一篇地址:( 译.持续更新 ) JavaScript 上分小技巧(一) 第三篇地址:( 译.持续更新 ) Java ...

  9. ( 译、持续更新 ) JavaScript 上分小技巧(一)

    感谢好友破狼提供的这篇好文章,也感谢写这些知识点的作者们和将他们整理到一起的作者.这是github上的一篇文章,在这里本兽也就只做翻译,由于本兽英语水平和编程能力都不咋地,如有不好的地方也请多理解体谅 ...

  10. 关于ASP.NET MVC开发设计中出现的问题与解决方案汇总 【持续更新】

    最近一直用ASP.NET MVC 4.0 +LINQ TO SQL来开发设计公司内部多个业务系统网站,在这其中发现了一些问题,也花了不少时间来查找相关资料或请教高人,最终都还算解决了,现在我将这些问题 ...

随机推荐

  1. list集合的一些小见解

    关于LIst集合 前言: 第一次写博客,有些东西可能总结的到位,发表一下自己的一些观点,欢迎大佬们点评和指教 正文: list集合可以分为ArrayLlst和LinkedList. ArrayList ...

  2. python解析html

    *参考 推荐BeautifulSoup http://blog.csdn.net/abclixu123/article/details/38502993 http://www.cnblogs.com/ ...

  3. Docker下mysql容器开启binlog日志(保留7天)

    现有需求开启用Docker容器启动的mysql数据库的binlog,以作为 日志记录 和 数据恢复,我们了解了MySQL的binlog日志的开启方式以及binlog日志的一些原理和常用操作,我们知道, ...

  4. NOIP比赛中如何加速c++的输入输出

    NOIP比赛中如何加速c++的输入输出 在竞赛中,遇到大数据时,往往需要更快的读取方式.由于比赛中输出一般规模较小,本文只讨论输入如何加速. 现在我们生成1000000个随机数,构成1000*1000 ...

  5. Python 【格式化字符串】

    print('血量:'+str(player_life)+' 攻击:'+str(player_attack)) 第一种格式化字符串 print('血量:%s 攻击:%s' % (player_life ...

  6. k8s-traefik默认80端口

    vim traefik.yaml kind: Deployment apiVersion: extensions/v1beta1 metadata: name: traefik-ingress-con ...

  7. 浅谈后缀数组SA

    这篇博客不打算讲多么详细,网上关于后缀数组的blog比我讲的好多了,这一篇博客我是为自己加深印象写的. 给你们分享了那么多,容我自私一回吧~ 参考资料:这位dalao的blog 一.关于求Suffix ...

  8. 3037 插板法+lucas

    先说下lucas定理 1)Lucas定理:p为素数,则有: (2)证明: n=(ak...a2,a1,a0)p = (ak...a2,a1)p*p + a0 =  [n/p]*p+a0 (注意 这里( ...

  9. C#通讯框架改写

    现有项目是利用C#的socket与PLC进行实时通讯,PLC有两种通讯模式——常规采集&高频采集. 其中常规采集大概在10ms左右发送一次数据,高频采集大概在2ms左右发送一次数据. 现有代码 ...

  10. 在开源UOJ的导航栏中添加新页面链接

    前言 刚用开源UOJ搭建OJ成功时就想在导航栏那里添加一个站内页面链接,无奈当时乱搞水平低,网上也没有教程,不晓得怎么弄 今天突然来了闲情乱搞一通,结果还真乱搞成了...特意写下为后来人少走点弯路 前 ...