C#中的數(shù)組用法詳解
如果需要使用同一類(lèi)型的多個(gè)對(duì)象,可以使用數(shù)組和集合(后面介紹)。C#用特殊的記號(hào)聲明,初始化和使用數(shù)組。Array類(lèi)在后臺(tái)發(fā)揮作用,它為數(shù)組中的元素排序和過(guò)濾提供了多個(gè)方法。使用枚舉器,可以迭代數(shù)組中的所有元素。
如果需要使用不同類(lèi)型的多個(gè)對(duì)象,可以使用Tuple(元組)類(lèi)型。
一.簡(jiǎn)單數(shù)組(一維數(shù)組)
數(shù)組是一種數(shù)據(jù)結(jié)構(gòu),它可以包含同一個(gè)類(lèi)型的多個(gè)元素。
1.數(shù)組的聲明
在聲明數(shù)組時(shí),先定義數(shù)組中的元素類(lèi)型,其后是一對(duì)空方括號(hào)和一個(gè)變量名。
int[] myArray;
2.數(shù)組的初始化
聲明了數(shù)組之后,就必須為數(shù)組分配內(nèi)存,以保存數(shù)組的所有元素。數(shù)組是引用類(lèi)型,所以必須給它分配堆上的內(nèi)存。為此,應(yīng)使用new運(yùn)算符,指定數(shù)組中元素的類(lèi)型和數(shù)量來(lái)初始化數(shù)組的變量。
myArray = new int[4];
在聲明和初始化數(shù)組后,變量myArray就引用了4個(gè)整數(shù)值,它們位于托管堆上:

在指定了數(shù)組的大小后,就不能重新設(shè)置數(shù)組的大小。如果事先不知道數(shù)組中應(yīng)包含多少個(gè)元素,就可以使用集合。
除了在兩個(gè)語(yǔ)句中聲明和初始化數(shù)組之外,還可以在一個(gè)語(yǔ)句中聲明和初始化數(shù)組:
int[] myArray = new int[4];
還可以使用數(shù)組初始化器為數(shù)組的每個(gè)元素復(fù)制。數(shù)組初始化器只能在聲明數(shù)組變量時(shí)使用,不能在聲明數(shù)組之后使用。
int[] myArray = new int[4]{1,3,5,7};
如果用花括號(hào)初始化數(shù)組,可以不指定數(shù)組的大小,因?yàn)榫幾g器會(huì)自動(dòng)統(tǒng)計(jì)元素的個(gè)數(shù):
int[] myArray = new int[]{1,3,5,7};
也可以使用更簡(jiǎn)單的形式:
int[] myArray = {1,3,5,7};
3.訪(fǎng)問(wèn)數(shù)組元素
在聲明和初始化數(shù)組之后,就可以使用索引器訪(fǎng)問(wèn)其中的元素了。數(shù)組只支持有整型參數(shù)的索引器。
索引器總是以0開(kāi)頭,表示第一個(gè)元素??梢詡鬟f給索引器的最大值是元素個(gè)數(shù)減1,因?yàn)樗饕龔?開(kāi)始:
int[] myArray = {1,3,5,7}; int v1 = myArray[0]; int v2 = myArray[1]; myArray[3] = 4;
可以使用數(shù)組的Length屬性獲取元素的個(gè)數(shù)。
4.數(shù)組中使用引用類(lèi)型
數(shù)組除了能聲明預(yù)定義類(lèi)型的數(shù)組,還可以聲明自定義類(lèi)型的數(shù)組。
public class Person
{
public string FirstName { get; set; }
public string LastName { get; set; }
public override string ToString()
{
return String.Format("{0} {1}", FirstName, LastName);
}
}
Person[] myPersons = new Person[2];
myPersons[0] = new Person { FirstName = "Ayrton", LastName = "Senna" };
myPersons[1] = new Person { FirstName = "Michael", LastName = "Schumacher" };如果數(shù)組中的元素是引用類(lèi)型,就必須為每個(gè)數(shù)組元素分配內(nèi)存。如果使用了數(shù)組中未分配內(nèi)存的元素,就會(huì)拋出NullReferenceException類(lèi)型的異常。
下面是內(nèi)存情況:

對(duì)自定義類(lèi)型也可以使用數(shù)組初始化器:
Person[] myPersons2 =
{
new Person { FirstName="Ayrton", LastName="Senna"},
new Person { FirstName="Michael", LastName="Schumacher"}
};二.多維數(shù)組
多維數(shù)組用兩個(gè)或多個(gè)整數(shù)來(lái)索引。
在C#中聲明多維數(shù)組,需要在方括號(hào)中加上逗號(hào)。數(shù)組在初始化時(shí)應(yīng)指定每一維的大?。ㄒ卜Q(chēng)為階)。
int[,] twoDim = new int[3,3]; twoDim[0,0] = 1; twoDim[0,1] = 2; twoDim[0,2] = 3; twoDim[1,0] = 4; twoDim[1,1] = 5; twoDim[1,2] = 6; twoDim[2,0] = 7; twoDim[2,1] = 8; twoDim[2,2] = 9;
聲明數(shù)組之后,就不能修改其階數(shù)了。
也可以使用初始化器來(lái)初始化多維數(shù)組:
int[,] twoDim ={
{1,2,3},
{4,5,6},
{7,8,9}
};使用數(shù)組初始化器時(shí),必須初始化數(shù)組的每個(gè)元素,不能遺漏任何元素。
聲明一個(gè)三位數(shù)組:
int[,,] threeDim ={
{{1,2},{3,4}},
{{5,6},{7,8}},
{{9,10},{11,12}}
};
Console.WriteLine(threeDim[0,1,1]);三.鋸齒數(shù)組
二維數(shù)組的大小對(duì)應(yīng)于一個(gè)矩形,而鋸齒數(shù)組的大小設(shè)置比較靈活,在鋸齒數(shù)組中,每一行都可以有不同的大小。
在聲明鋸齒數(shù)組時(shí),要依次放置左右括號(hào)。在初始化鋸齒數(shù)組時(shí),只在第一對(duì)方括號(hào)中設(shè)置該數(shù)組包含的行數(shù)。定義各行中元素個(gè)數(shù)的第二個(gè)方括號(hào)設(shè)置為空,因?yàn)檫@類(lèi)數(shù)組的每一行包含不同的元素個(gè)數(shù)。之后,為每一行指定行中的元素個(gè)數(shù):
int[][] jagged = new int[3][];
jagged[0] = new int[2]{1,2};
jagged[1] = new int[4]{3,4,5,6};
jagged[2] = new int[3]{7,8};迭代鋸齒數(shù)組中的所有元素的代碼可以放在嵌套的for循環(huán)中。在外層的for循環(huán)中迭代每一行,在內(nèi)層的for循環(huán)中迭代一行中的每個(gè)元素:
for(int row = 0;row<jagged.Length;row++)
{
for(int element = 0;element<jagged[row].Length;element++)
{
Console.WriteLine("row:{0}, element:{1},value:{2}",row,element,jagged[row][element]);
}
}四.Array類(lèi)
用方括號(hào)聲明數(shù)組是C#中使用Array類(lèi)的表示法。在后臺(tái)使用C#語(yǔ)法,會(huì)創(chuàng)建一個(gè)派生自抽象基類(lèi)Array的新類(lèi)。這樣,就可以使用Array類(lèi)為每個(gè)C#數(shù)組定義的方法和屬性了。
Array類(lèi)實(shí)現(xiàn)的其它屬性有LongLength和Rank。如果數(shù)組包含的元素個(gè)數(shù)超出了整數(shù)的取值范圍,就可以使用LongLength屬性來(lái)獲得元素個(gè)數(shù)。使用Rank屬性可以獲得數(shù)組的維數(shù)。
1.創(chuàng)建數(shù)組
Array類(lèi)是一個(gè)抽象類(lèi),所以不能使用構(gòu)造函數(shù)來(lái)創(chuàng)建數(shù)組。但除了使用C#語(yǔ)法創(chuàng)建數(shù)組實(shí)例之外,還可以使用靜態(tài)方法CreateInstance()創(chuàng)建數(shù)組。如果事先不知道元素的類(lèi)型,該靜態(tài)方法就很有用,因?yàn)轭?lèi)型可以作為T(mén)ype對(duì)象傳遞給CreateInstance()方法。
CreateInstance()方法的第一個(gè)參數(shù)是元素的類(lèi)型,第二個(gè)參數(shù)定義數(shù)組的大小。
可以使用SetValue()方法設(shè)置對(duì)應(yīng)元素的值,用GetValue()方法讀取對(duì)應(yīng)元素的值。
Array intArray1 = Array.CreateInstance(typeof(int), 5);
for (int i = 0; i < 5; i++)
{
intArray1.SetValue(33, i);
}
for (int i = 0; i < 5; i++)
{
Console.WriteLine(intArray1.GetValue(i));
}還可以將已經(jīng)創(chuàng)建的數(shù)組強(qiáng)制轉(zhuǎn)換稱(chēng)聲明為int[]的數(shù)組:
int[] intArray2 = (int[])intArray1;
CreateInstance()方法有許多重載版本,可以創(chuàng)建多維數(shù)組和索引不基于0的數(shù)組。
//創(chuàng)建一個(gè)2X3的二維數(shù)組,第一維基于1,第二維基于10:
int[] lengths = { 2, 3 };
int[] lowerBounds = { 1, 10 };
Array racers = Array.CreateInstance(typeof(Person), lengths, lowerBounds);
racers.SetValue(new Person { FirstName = "Alain", LastName = "Prost" }, index1: 1, index2: 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 = "Michael", 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.復(fù)制數(shù)組
因?yàn)閿?shù)組是引用類(lèi)型,所以將一個(gè)數(shù)組變量賦予另一個(gè)數(shù)組變量,就會(huì)得到兩個(gè)引用同一數(shù)組的變量。
數(shù)組實(shí)現(xiàn)ICloneable接口。這個(gè)接口定義的Clone()方法會(huì)復(fù)制數(shù)組,創(chuàng)建數(shù)組的淺表副本。
如果數(shù)組的元素是值類(lèi)型,Clone()方法會(huì)復(fù)制所有值:
int[] a1 = {1,2};
int[] a2 = (int[])a1.Clone();如果數(shù)組包含引用類(lèi)型,只復(fù)制引用。
除了使用Clone()方法之外,還可以使用Array.Copy()方法創(chuàng)建淺表副本。
Person[] beatles = {
new Person { FirstName="John", LastName="Lennon" },
new Person { FirstName="Paul", LastName="McCartney" }
};
Person[] beatlesClone = (Person[])beatles.Clone();
Person[] beatlesClone2 = new Person[2];
Array.Copy(beatlesClone,beatlesClone2,2);//注意與Clone的語(yǔ)法區(qū)別,Copy需要傳遞階數(shù)相同的已有數(shù)組。(還可以使用CopyTo()方法)3.排序
Array類(lèi)使用快速排序算法對(duì)數(shù)組中的元素進(jìn)行排序。Sort()方法需要數(shù)組中的元素實(shí)現(xiàn)IComparable接口。因?yàn)楹?jiǎn)單類(lèi)型(如String,Int32)實(shí)現(xiàn)IComparable接口,所以可以對(duì)包含這些類(lèi)型的元素排序。
string[] names = {
"Christina Aguilera",
"Shakira",
"Beyonce",
"Gwen Stefani"
};
Array.Sort(names);
foreach (string name in names)
{
Console.WriteLine(name);
}如果對(duì)數(shù)組使用使用自定義類(lèi),就必須實(shí)現(xiàn)IComparable接口。這個(gè)接口只定義了一個(gè)方法CompareTo()方法,如果要比較的對(duì)象相等,該方法就返回0.如果該實(shí)例應(yīng)排在參數(shù)對(duì)象的前面,該方法就返回小于i0de值。如果該實(shí)例應(yīng)排在參數(shù)對(duì)象的后面,該方法就返回大于0的值。
public class Person : IComparable<Person>
{
public string FirstName { get; set; }
public string LastName { get; set; }
public override string ToString()
{
return String.Format("{0} {1}",
FirstName, LastName);
}
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;
}
}客戶(hù)端代碼:
Person[] persons = {
new Person { FirstName="Damon", LastName="Hill" },
new Person { FirstName="Niki", LastName="Lauda" },
new Person { FirstName="Ayrton", LastName="Senna" },
new Person { FirstName="Graham", LastName="Hill" }
};
Array.Sort(persons);
foreach (Person p in persons)
{
Console.WriteLine(p);
}如果Person對(duì)象的排序方式與上述不同,或者不能修改在數(shù)組中用作元素的類(lèi),就可以實(shí)現(xiàn)IComparer接口或IComparer<T>接口。這兩個(gè)接口定義了方法Compare()方法。機(jī)型比較的類(lèi)必須實(shí)現(xiàn)這兩個(gè)接口之一。
public enum PersonCompareType
{
FirstName,
LastName
}
//通過(guò)使用實(shí)現(xiàn)了IComparer<T> 泛型接口的PersonComparer類(lèi)比較Person對(duì)象數(shù)組。
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 x.FirstName.CompareTo(y.FirstName);
case PersonCompareType.LastName:
return x.LastName.CompareTo(y.LastName);
default:
throw new ArgumentException(
"unexpected compare type");
}
}
#endregion
}客戶(hù)端代碼:
Person[] persons = {
new Person { FirstName="Damon", LastName="Hill" },
new Person { FirstName="Niki", LastName="Lauda" },
new Person { FirstName="Ayrton", LastName="Senna" },
new Person { FirstName="Graham", LastName="Hill" }
};
Array.Sort(persons,
new PersonComparer(PersonCompareType.FirstName));
foreach (Person p in persons)
{
Console.WriteLine(p);
}五.數(shù)組作為參數(shù)
數(shù)組可以作為參數(shù)傳遞給方法,也可以從方法中返回。
1.數(shù)組協(xié)變
數(shù)組支持協(xié)變。這表示數(shù)組可以聲明為基類(lèi),其派生類(lèi)型的元素可以賦值于數(shù)組元素。
static void DisPlay(object[] o)
{
//..
}可以給該方法傳遞一個(gè)Person[]。
數(shù)組協(xié)變只能用于引用類(lèi)型,不能用于值類(lèi)型。
2.ArraySegment<T>
結(jié)構(gòu)ArraySegment<T>表示數(shù)組的一段。如果需要使用不同的方法處理某個(gè)大型數(shù)組的不同部分,那么可以把相應(yīng)的數(shù)組部分復(fù)制到各個(gè)方法。
ArraySegment<T>結(jié)構(gòu)包含了關(guān)于數(shù)組段的信息(偏移量和元素個(gè)數(shù))。
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]
{
new ArraySegment<int>(ar1, 0, 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];
}
}
return sum;
}數(shù)組段不復(fù)制原數(shù)組的元素,但原數(shù)組可以通過(guò)ArraySegment<T>訪(fǎng)問(wèn)。如果數(shù)組段中的元素改變了,這些變化就會(huì)反映到原數(shù)組中。
六.枚舉集合
在foreach語(yǔ)句中使用枚舉,可以迭代集合中的元素,且無(wú)需知道集合中元素的個(gè)數(shù)。foreach語(yǔ)句使用一個(gè)枚舉器。foreach會(huì)調(diào)用實(shí)現(xiàn)了IEnumerable接口的集合類(lèi)中的GetEumerator()方法。GetEumerator()方法返回一個(gè)實(shí)現(xiàn)IEnumerator接口的對(duì)象枚舉。foreach語(yǔ)句就可以使用IEnumerable接口迭代集合了。
GetEumerator()方法在IEnumerable接口中定義。
1.IEnumerator接口
foreach語(yǔ)句使用IEnumerator接口的方法和屬性,迭代集合中所有元素。IEnumerator接口定義了Current屬性,來(lái)返回光標(biāo)所在的元素,該接口的MoveNext()方法移動(dòng)到集合的下一個(gè)元素上,如果有這個(gè)元素,該方法就返回true。如果集合不再有更多的元素,該方法就返回false.
這個(gè)接口的泛型版本IEnumerator<T>派生自接口IDisposable,因此定義了Dispose()方法,來(lái)清理枚舉器占用的資源。
2.foreach語(yǔ)句
C#中foreach語(yǔ)句不會(huì)解析為IL代碼中的foreach語(yǔ)句。C#編譯器會(huì)把foreach語(yǔ)句轉(zhuǎn)換為IEnumerator接口的方法和屬性。
Person[] persons = {
new Person { FirstName="Damon", LastName="Hill" },
new Person { FirstName="Niki", LastName="Lauda" },
new Person { FirstName="Ayrton", LastName="Senna" },
new Person { FirstName="Graham", LastName="Hill" }
};
foreach (Person p in persons)
{
Console.WriteLine(p);
}foreach語(yǔ)句會(huì)解析為下面的代碼:
IEnumerator<Person> enumerator = persons.GetEumerator();
while(enumerator.MoveNext())
{
Person p = enumerator.Current;
Console.WriteLine(p);
}3.yield語(yǔ)句
在C#2.0之前,foreach語(yǔ)句可以輕松的迭代集合,但創(chuàng)建枚舉器需要做大量的工作。C#2.0添加了yield語(yǔ)句,以便創(chuàng)建枚舉器。
yield return 語(yǔ)句返回集合的一個(gè)元素,并移動(dòng)到下一個(gè)元素。yield break可停止迭代。
下面的例子實(shí)現(xiàn)返回兩個(gè)字符串:
public class HelloCollection
{
public IEnumerator<string> GetEnumerator()
{
yield return "Hello";
yield return "World";
}
}客戶(hù)端代碼:
var helloCollection = new HelloCollection();
foreach (string s in helloCollection)
{
Console.WriteLine(s);
}包含yield語(yǔ)句的方法或?qū)傩砸卜Q(chēng)為迭代塊。迭代塊必須聲明為返回IEnumerator或IEnumerable接口,或者這些接口的泛型版本。這個(gè)塊可以包含多條yield return語(yǔ)句或yield break語(yǔ)句,但不能包含return語(yǔ)句。
使用迭代塊,編譯器會(huì)生成一個(gè)yield類(lèi)型,其中包含一個(gè)狀態(tài)機(jī),如下面代碼所示:
yield類(lèi)型實(shí)現(xiàn)IEnumerator和IDisposable接口的方法和屬性。下面的例子可以把yield類(lèi)型看作內(nèi)部類(lèi)Enumerator。外部類(lèi)的GetEnumerator()方法實(shí)例化并返回一個(gè)新的yield類(lèi)型。在yield類(lèi)型中,變量state定義了迭代的當(dāng)前位置,每次調(diào)用MoveNext()時(shí),當(dāng)前位置都會(huì)改變。MoveNext()封裝了迭代塊的代碼,并設(shè)置了current變量的值,從而使Current屬性根據(jù)位置返回一個(gè)對(duì)象。
public class HelloCollection
{
public IEnumerator<string> GetEnumerator()
{
return new Enumerator(0);
}
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 0:
current="hello";
state =1;
return true;
case 1:
current="world";
state =2;
return true;
case 2:
break;
}
return false;
}
void System.Collection>IEnumerator.Reset()
{
throw new NotSupportedException();
}
string System.Collections.Generic.IEnumerator<string>.Current
{
get
{
return current;
}
}
object System.Collections.IEnumerator.Current
{
get
{
return current;
}
}
void IDisposable.Dispose()
{}
}
}yield語(yǔ)句會(huì)產(chǎn)生一個(gè)枚舉器,而不僅僅生成一個(gè)包含的項(xiàng)的列表。這個(gè)枚舉器通過(guò)foreach語(yǔ)句調(diào)用。從foreach中依次訪(fǎng)問(wèn)每一項(xiàng),就會(huì)訪(fǎng)問(wèn)枚舉器。這樣就可以迭代大量的數(shù)據(jù),而無(wú)需一次把所有的數(shù)據(jù)都讀入內(nèi)存。
(1).迭代集合的不同方式
可以使用yield return語(yǔ)句,以不同方式迭代集合。
類(lèi)MusicTitles可以用默認(rèn)方式通過(guò)GetEnumerator()方法迭代標(biāo)題,該方法不必在代碼中編寫(xiě),也可以用Reverse()逆序迭代標(biāo)題,用Subset()方法迭代子集合:
public class MusicTitles
{
string[] names = {
"Tubular Bells", "Hergest Ridge",
"Ommadawn", "Platinum" };
public IEnumerator<string> GetEnumerator()
{
for (int i = 0; i < 4; i++)
{
yield return names[i];
}
}
public IEnumerable<string> Reverse()
{
for (int i = 3; i >= 0; i--)
{
yield return names[i];
}
}
public IEnumerable<string> Subset(int index, int length)
{
for (int i = index; i < index + length;i++)
{
yield return names[i];
}
}
}客戶(hù)端代碼:
var titles = new MusicTitles();
foreach (var title in titles)
{
Console.WriteLine(title);
}
Console.WriteLine();
Console.WriteLine("reverse");
foreach (var title in titles.Reverse())
{
Console.WriteLine(title);
}
Console.WriteLine();
Console.WriteLine("subset");
foreach (var title in titles.Subset(2, 2))
{
Console.WriteLine(title);
}(2).用yield return 返回枚舉器
public class GameMoves
{
private IEnumerator cross;
private IEnumerator circle;
public GameMoves()
{
cross = Cross();
circle = Circle();
}
private int move = 0;
const int MaxMoves = 9;
public IEnumerator Cross()
{
while (true)
{
Console.WriteLine("Cross, move {0}", move);
if (++move >= MaxMoves)
yield break;
yield return circle;
}
}
public IEnumerator Circle()
{
while (true)
{
Console.WriteLine("Circle, move {0}", move);
if (++move >= MaxMoves)
yield break;
yield return cross;
}
}
}客戶(hù)端代碼:
var game = new GameMoves();
IEnumerator enumerator = game.Cross();
while (enumerator.MoveNext())
{
enumerator = enumerator.Current as IEnumerator;
}這樣會(huì)交替調(diào)用Cross()和Circle()方法。
七.元組(Tuple)
元組可以合并不同類(lèi)型的對(duì)象。元組起源于函數(shù)編程語(yǔ)言,如F#。在.NET Framework中,元組可用于所有的.Net語(yǔ)言。
.NET Framework定義了8個(gè)泛型Tuple類(lèi)和一個(gè)靜態(tài)Tuple類(lèi),它們用作元組的工廠(chǎng)。不同的泛型Tuple類(lèi)支持不同數(shù)量的元素。如,Tuple<T1>包含一個(gè)元素,Tuple<T1,T2>包含兩個(gè)元素。
Tuple<string, string> name = new Tuple<string, string>("Jochen", "Rindt");元組也可以用靜態(tài)Tuple類(lèi)的靜態(tài)Create()方法創(chuàng)建。Create()方法的泛型參數(shù)定了要實(shí)例化的元組類(lèi)型:
public static Tuple<int, int> Divide(int dividend, int divisor)
{
int result = dividend / divisor;
int reminder = dividend % divisor;
return Tuple.Create<int, int>(result, reminder);
}可以用屬性Item1和Item2訪(fǎng)問(wèn)元組的項(xiàng):
var result = Divide(5, 2);
Console.WriteLine("result of division: {0}, reminder: {1}", result.Item1, result.Item2);如果元組包含的項(xiàng)超過(guò)8個(gè),就可以使用帶8個(gè)參數(shù)的Tuple類(lèi)定義。最后一個(gè)模板參數(shù)是TRest,表示必須給它傳遞一個(gè)元組。這樣,就可以創(chuàng)建帶任意個(gè)參數(shù)的元組了。
var tuple = Tuple.Create<string, string, string, int, int, int, double, Tuple<int, int>>( "Stephanie", "Alina", "Nagel", 2009, 6, 2, 1.37, Tuple.Create<int, int>(52, 3490));
八.結(jié)構(gòu)比較
數(shù)組和元組都實(shí)現(xiàn)接口IStructuralEquatable和IStructuralComparable。這兩個(gè)接口不僅可以比較引用,還可以比較內(nèi)容。這些接口都是顯式實(shí)現(xiàn)的,所以在使用時(shí)需要把數(shù)組和元組強(qiáng)制轉(zhuǎn)換為這個(gè)接口。
IStructuralEquatable接口用于比較兩個(gè)元組或數(shù)組是否有相同的內(nèi)同,IStructuralComparable接口用于給元組或數(shù)組排序。
IStructuralEquatable接口示例:
編寫(xiě)實(shí)現(xiàn)IEquatable接口的Person類(lèi),IEquatable接口定義了一個(gè)強(qiáng)類(lèi)型化的Equals()方法,比較FirstName和LastName的值:
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);
}
public override bool Equals(object obj)
{
if (obj == null)
return base.Equals(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)
return base.Equals(other);
return this.FirstName == other.FirstName && this.LastName == other.LastName;
}
#endregion
}創(chuàng)建兩個(gè)包含相同內(nèi)容的Person類(lèi)型的數(shù)組:
var janet = new Person { FirstName = "Janet", LastName = "Jackson" };
Person[] persons1 = { new Person { FirstName = "Michael", LastName = "Jackson" }, janet };
Person[] persons2 = { new Person { FirstName = "Michael", LastName = "Jackson" }, janet };由于兩個(gè)變量引用兩個(gè)不同數(shù)組,所以!=返回True:
if (persons1 != persons2)
Console.WriteLine("not the same reference");對(duì)于IStructuralEquatable接口定義的Equals方法,第一個(gè)參數(shù)是object類(lèi)型,第二個(gè)參數(shù)是IEqualityComparer類(lèi)型。調(diào)用這個(gè)方法時(shí),通過(guò)傳遞一個(gè)實(shí)現(xiàn)了EqualityComparer<T>的對(duì)象,就可以定義如何進(jìn)行比較。通過(guò)EqualityComparer<T>類(lèi)完成IEqualityComparer的一個(gè)默認(rèn)實(shí)現(xiàn)。這個(gè)實(shí)現(xiàn)檢查T(mén)類(lèi)型是否實(shí)現(xiàn)了IEquatable接口,并調(diào)用IEquatable.Equals()方法。如果該類(lèi)沒(méi)有實(shí)現(xiàn)IEquatable接口,就調(diào)用Object基類(lèi)中Equals()方法:
if ((persons1 as IStructuralEquatable).Equals(persons2, EqualityComparer<Person>.Default))
{
Console.WriteLine("the same content");
}元組示例:
Tuple<>類(lèi)提供了兩個(gè)Epuals()方法:一個(gè)重寫(xiě)了Object基類(lèi)中的Epuals方法,并把object作為參數(shù),第二個(gè)由IStructuralEquatable接口定義,并把object和IEqualityComparer作為參數(shù)。
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");這個(gè)方法使用EqualityComparer<object>.Default獲取一個(gè)ObjectEqualityComparer<object>,以進(jìn)行比較。這樣就會(huì)調(diào)用Object.Equals()方法比較元組的每一項(xiàng):
if (t1.Equals(t2))
Console.WriteLine("equals returns true");還可以使用TupleComparer類(lèi)創(chuàng)建一個(gè)自定義的IEqualityComparer
TupleComparer tc = new TupleComparer();
if ((t1 as IStructuralEquatable).Equals(t2, tc))
{
Console.WriteLine("yes, using TubpleComparer");
}
class TupleComparer : IEqualityComparer
{
#region IEqualityComparer Members
public new bool Equals(object x, object y)
{
bool result = x.Equals(y);
return result;
}
public int GetHashCode(object obj)
{
return obj.GetHashCode();
}
#endregion
}以上就是本文的全部?jī)?nèi)容,希望對(duì)大家的學(xué)習(xí)有所幫助,也希望大家多多支持腳本之家。
相關(guān)文章
winform基于異步委托實(shí)現(xiàn)多線(xiàn)程搖獎(jiǎng)器
這篇文章主要介紹了winform基于異步委托實(shí)現(xiàn)多線(xiàn)程搖獎(jiǎng)器的方法,包含了線(xiàn)程的運(yùn)用及隨機(jī)數(shù)的生成,需要的朋友可以參考下2014-10-10
C# 使用WPF 用MediaElement控件實(shí)現(xiàn)視頻循環(huán)播放
在WPF里用MediaElement控件,實(shí)現(xiàn)一個(gè)循環(huán)播放單一視頻的程序,同時(shí)可以控制視頻的播放、暫停、停止。這篇文章給大家介紹了C# 使用WPF 用MediaElement控件實(shí)現(xiàn)視頻循環(huán)播放,需要的朋友參考下吧2018-04-04
Unity 百度AI實(shí)現(xiàn)人像動(dòng)漫化效果
這篇文章主要介紹了Unity如何接入百度AI接口, 運(yùn)用對(duì)抗生成網(wǎng)絡(luò)技術(shù),為用戶(hù)量身定制千人千面的二次元?jiǎng)勇蜗?,并支持通過(guò)參數(shù)設(shè)置,生成二次元?jiǎng)勇讼?。感興趣的可以學(xué)習(xí)一下2022-01-01
C#實(shí)現(xiàn)的SN快速輸入工具實(shí)例
這篇文章主要介紹了C#實(shí)現(xiàn)的SN快速輸入工具,以實(shí)例的形式詳細(xì)講述了C#實(shí)現(xiàn)序列號(hào)快速輸入的方法,是非常實(shí)用的技巧,需要的朋友可以參考下2014-11-11
C#基于TimeSpan實(shí)現(xiàn)倒計(jì)時(shí)效果的方法
這篇文章主要介紹了C#基于TimeSpan實(shí)現(xiàn)倒計(jì)時(shí)效果的方法,比較實(shí)用的功能,需要的朋友可以參考下2014-08-08
C#部署數(shù)據(jù)庫(kù)及IIS站點(diǎn)
這篇文章主要為大家詳細(xì)介紹了C#部署數(shù)據(jù)庫(kù)及IIS站點(diǎn)的相關(guān)資料,具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下2018-03-03

