1.C#数组基本特性
1)数组是存储的引用,引用的元素存放在托管堆,如果元素是值类型任意初始化方式都可以,如果元素是引用类型那么初始化时侯元素要new出来。2)多维逗号隔开就可以了,长度用Length。数组类CRL编译后使得继承自Array类,也就是继承自IEnumerable,IStructuralComparable等,IEnumerable有 IEnumerator GetEnumerator()函数迭代器有Current,MoveNext,Reset方法,有Array基类Length属性等, foreach特性就是基于CRL定义的这些接口实现的。
3)数组的访问只支持整型的索引器。内部自定义对象数组可以用整型索引器访问的,但是提供给外部可以定义索引器,索引器就是属性只是多了参入参数,this和value的一些标识。
4)数组拷贝只支持浅拷贝,有Clone()系统会帮申请内存,Copy()要自己创建引用内存拷贝到已有数组(都是引用类型的元素);深拷贝要一个个迭代生成新对象。
5)数组支持协变,派生类可以赋值给基类数组,调用基类对象定义的方法。
6)对象数组创建:
myPersons[0] = new Person { FirstName = "Ayrton" };//, LastName = "Senna" 属性不一定要使用
myPersons[1] = new Person { FirstName = "Michael", LastName = "Schumacher" };
Array抽象类从静态方法创建数组:
// 长度是两维,每位大小是3
int[] lengths = { 3, 3 };
// 第一维1最小后面递增,第二维从10开始后面第二维重复
int[] lowerBounds = { 1, 10 };
Array racers = Array.CreateInstance(typeof(Person), lengths, lowerBounds);
racers.SetValue(new Person { FirstName = "Alain", LastName = "Prost" }, 1, 10);
racers.SetValue(new Person{FirstName = "Emerson",LastName = "Fittipaldi"}, 1, 11);
racers.SetValue(new Person { FirstName = "Ayrton", LastName = "Senna" }, 1, 12);
racers.SetValue(new Person { FirstName = "Ralf", LastName = "Schumacher" }, 2, 10);
racers.SetValue(new Person { FirstName = "Fernando", LastName = "Alonso" }, 2, 11);
racers.SetValue(new Person { FirstName = "Jenson", LastName = "Button" }, 2, 12);
Person[,] racers2 = (Person[,])racers;
Person first = racers2[1, 10];
Person last = racers2[2, 12];
2.数组片段ArraySegment对象
可以获取片段,传入使用片段不需要加起始偏移和个数了。
namespace ArraySegmentSample
{
class Program
{
static void Main()
{
int[] ar1 = { 1, 4, 5, 11, 13, 18 };
int[] ar2 = { 3, 4, 5, 18, 21, 27, 33 };
var segments = new ArraySegment<int>[2]
{
// 对arg1,起始0,数量为3
new ArraySegment<int>(ar1, 0, 3),
// 对arg2,起始3,数量为3
new ArraySegment<int>(ar2, 3, 3)
};
var sum = SumOfSegments(segments);
Console.WriteLine("sum of all segments: {0}", sum);
}
static int SumOfSegments(ArraySegment<int>[] segments)
{
int sum = 0;
foreach (var segment in segments)
{
for (int i = segment.Offset; i < segment.Offset + segment.Count; i++)
{
sum += segment.Array[i];
// 如果改变了值会直接反应到原数组中
segment.Array[i] = 100;
}
}
return sum;
}
}
}
3.数组的比较
数组和元组排序可用:IStructuralComparable
相等判断可用:IStructuralEquatable
判断排序:
因为Sort函数要求调用泛型类型的CompareTo<T>方法,如果是默认类型的就不用处理,如果是自定义类型那么要继承IComparable<T>接口,实现CompareTo<T>方法:
public class Person : IComparable<Person>
{
// this相比other,小于返回负数,等于返回0,大于返回正数
public int CompareTo(Person other)
{
if (other == null) throw new ArgumentNullException("other");
int result = this.LastName.CompareTo(other.LastName);
if (result == 0)
{
result = this.FirstName.CompareTo(other.FirstName);
}
return result;
}
}
调用时候:
Array.Sort(persons);
也可以继承IComparer<Person>,实现public int Compare(Person x, Person y)函数。
例如:
public class PersonComparer : IComparer<Person>
{
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 x.FirstName.CompareTo(y.FirstName);
case PersonCompareType.LastName:
return x.LastName.CompareTo(y.LastName);
default:
throw new ArgumentException(
"unexpected compare type");
}
}
}
调用时候:
Array.Sort(persons, new PersonComparer(PersonCompareType.FirstName));
相等判断:
一般重写Object的Equal就可以。如果要比较对象数组那么需要,强转为IStructuralEquatable使用Equals方法,使用实例化EqualityComparer泛型,泛型类型实现IEquatable接口,重写Equals方法,因为Object也有该方法,所以需要new关键字修饰下。
实例:
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
namespace Wrox.ProCSharp.Arrays
{
public class Person : IEquatable<Person>
{
public int Id { get; private set; }
public string FirstName { get; set; }
public string LastName { get; set; }
public override string ToString()
{
return String.Format("{0}, {1} {2}", Id, FirstName, LastName);
}
// 一般情况下判断是否相等,重载Object类型的Equals就可以了,不需要转换到IStructuralEquatable类型
// 实现IEquatable接口方法
public override bool Equals(object obj)
{
throw new Exception("xx");
if (obj == null) throw new ArgumentNullException("obj");
return Equals(obj as Person);
}
public override int GetHashCode()
{
return Id.GetHashCode();
}
#region IEquatable<Person> Members
public bool Equals(Person other)
{
if (other == null) throw new ArgumentNullException("other");
bool bEqual1 = this.FirstName == other.FirstName;
bool bEqual2 = this.LastName == other.LastName;
return bEqual1 && bEqual2;
}
#endregion
}
}
using System;
using System.Collections;
using System.Collections.Generic;
using System.Linq;
using System.Text;
namespace Wrox.ProCSharp.Arrays
{
class TupleComparer : IEqualityComparer
{
#region IEqualityComparer Members
public new bool Equals(object x, object y)
{
return x.Equals(y);
}
public int GetHashCode(object obj)
{
return obj.GetHashCode();
}
#endregion
}
class Program
{
static void Main()
{
var janet = new Person { FirstName = "Janet", LastName = "Jackson" };
var janet2 = new Person { FirstName = "Janet", LastName = "Jackson" };
Person[] persons1 = { new Person { FirstName = "Michael", LastName = "Jackson" }, janet };
Person[] persons2 = { new Person { FirstName = "Michael", LastName = "Jackson" }, janet };
if (persons1 != persons2)
Console.WriteLine("not the same reference");
// 继承自Object的Equals对象使用时OK,如果是对象数组使用就有问题了
if (!janet.Equals(janet2))
{
Console.WriteLine("janet equals returns false - not the same reference");
}
else
{
Console.WriteLine("janet equals returns true, the same reference");
}
if (!persons1.Equals(persons2))
Console.WriteLine("persons equals returns false - not the same reference");
// 需要强转为IStructuralEquatable类型,IStructuralEquatable类型的Equals会调用EqualityComparer
// EqualityComparer会检查泛型类Person是否继承了IEquatable接口实现了Equals方法,没有则调用Object的方法
if ((persons1 as IStructuralEquatable).Equals(persons2, EqualityComparer<Person>.Default))
{
Console.WriteLine("the same content");
}
var t1 = Tuple.Create<int, string>(1, "Stephanie");
var t2 = Tuple.Create<int, string>(1, "Stephanie");
if (t1 != t2)
Console.WriteLine("not the same reference to the tuple");
// 就是一个对象,所以直接调用正确
if (t1.Equals(t2))
Console.WriteLine("equals returns true");
// 强转为IStructuralEquatable,调用Equals会要求被比较的参数传入一个TupleComparer对象,使用TupleComparer中
// 定义的Equals方法,没有则使用父类的Equals.
if ((t1 as IStructuralEquatable).Equals(t2, new TupleComparer()))
{
Console.WriteLine("yes, using TubpleComparer");
}
}
}
}
使用见:
if ((persons1 as IStructuralEquatable).Equals(persons2, EqualityComparer<Person>.Default))
4.元组
元组Tuple就是一个可以存放不同类型的数组容器,暂时觉得作用不大,存放凌乱难以维护,如果是需要函数式编程的话作用会比较大。
8个泛型个数类型的Tuple和一个静态类型的Tuple::Create可以创建需要的元组,方法元组元素用tupbleObj.ItemX。