人人做人人澡人人爽欧美,国产主播一区二区,久久久精品五月天,羞羞视频在线观看免费

當(dāng)前位置:蘿卜系統(tǒng)下載站 > 技術(shù)開發(fā)教程 > 詳細(xì)頁(yè)面

C#2.0語(yǔ)言規(guī)范(4)迭代器

C#2.0語(yǔ)言規(guī)范(4)迭代器

更新時(shí)間:2022-07-01 文章作者:未知 信息來(lái)源:網(wǎng)絡(luò) 閱讀次數(shù):

4.1 迭代器塊
一個(gè)迭代器塊(iterator block)是一個(gè)能夠產(chǎn)生有序的值序列的塊。迭代器塊和普通語(yǔ)句塊的區(qū)別就是其中出現(xiàn)的一個(gè)或多個(gè)yield語(yǔ)句。

yield return語(yǔ)句產(chǎn)生迭代的下一個(gè)值。
yield break語(yǔ)句表示迭代完成。
只要相應(yīng)的函數(shù)成員的返回值類型是一個(gè)枚舉器接口(見4.1.1)或是一個(gè)可枚舉接口(見4.1.2),一個(gè)迭代器塊就可以用作方法體、運(yùn)算符體或訪問器體。

迭代器塊并不是C#語(yǔ)法中的獨(dú)立元素。它們受多種因素的制約,并且對(duì)函數(shù)成員聲明的語(yǔ)義有很大影響,但在語(yǔ)法上它們只是塊(block)。

當(dāng)一個(gè)函數(shù)成員用一個(gè)迭代器塊來(lái)實(shí)現(xiàn)時(shí),如果函數(shù)成員的形式參數(shù)列表指定了ref或out參數(shù),則會(huì)引起編譯錯(cuò)誤。

如果在迭代器塊中出現(xiàn)了return語(yǔ)句,則會(huì)因此編譯錯(cuò)誤(但yield return語(yǔ)句是允許的)。

如果迭代器塊包含不安全上下文,則會(huì)引起編譯錯(cuò)誤。一個(gè)迭代器塊必須定義在一個(gè)安全的上下文中,即使它的聲明嵌套在一個(gè)不安全上下文中。

4.1.1 枚舉器接口
枚舉器(enumerator)接口包括非泛型接口System.Collections.IEnumerator和泛型接口System.Collections.Generic.IEnumerator<T>的所有實(shí)例化。在這一章中,這些接口將分別稱作IEnumerator和IEnumerator<T>。

4.1.2 可枚舉接口
可枚舉(enumerable)接口包括非泛型接口System.Collections.IEnumerable和泛型接口System.Collections.Generic.IEnumerable<T>。在這一章中,這些接口分別稱作IEnumerable和IEnumerable<T>。

4.1.3 生成類型
一個(gè)迭代器塊能夠產(chǎn)生一個(gè)有序的值序列,其中所有的制具有相同的類型。這個(gè)類型稱為迭代器塊的生成類型(yield type)。

用于實(shí)現(xiàn)一個(gè)返回IEnumerator或IEnumerable的函數(shù)成員的迭代器塊的生成類型為object。
用于是下一個(gè)返回IEnumerator<T>或IEnumerable<T>的函數(shù)成員的迭代器塊的生成類型為T。
4.1.4 this訪問
在一個(gè)類的一個(gè)實(shí)例成員中的迭代器塊里,表達(dá)式this是一個(gè)值。這個(gè)值的類型就是出現(xiàn)這種用法的類,并且它是對(duì)被調(diào)用的方法所在的對(duì)象的一個(gè)引用。

在一個(gè)結(jié)構(gòu)的一個(gè)實(shí)例成員中的迭代器塊里,表達(dá)式this是一個(gè)變量。這個(gè)變量的類型就是出現(xiàn)這種用法的結(jié)構(gòu)。這個(gè)變量存貯了對(duì)被調(diào)用成員所在結(jié)構(gòu)的一個(gè)拷貝。結(jié)構(gòu)的實(shí)例成員中的迭代器塊里的this變量和以該結(jié)構(gòu)為類型的值變量完全一樣。

4.2 Enumerator對(duì)象
如果一個(gè)函數(shù)成員使用了迭代器塊來(lái)返回一個(gè)枚舉器接口類型,對(duì)該函數(shù)成員的調(diào)用不會(huì)立即執(zhí)行迭代器塊中的代碼,而是建立并返回一個(gè)枚舉器對(duì)象。這個(gè)對(duì)象封裝了迭代器塊中指定的代碼,而對(duì)迭代器中指定的代碼的執(zhí)行發(fā)生在調(diào)用該枚舉器對(duì)象的MoveNext()方法時(shí)。一個(gè)枚舉器對(duì)象具有如下特征:

它實(shí)現(xiàn)了IEnumerator和IEnumerator<T>,這里T是迭代器塊的生成類型。
它實(shí)現(xiàn)了System.IDisposable。
它用傳遞給函數(shù)成員的參數(shù)值(如果有的話)和實(shí)例值進(jìn)行初始化。
它有四個(gè)可能的狀態(tài):before、running、suspended和after,其初始狀態(tài)為before。
典型的枚舉器對(duì)象是由編譯器自動(dòng)生成的封裝了迭代器塊中的代碼并實(shí)現(xiàn)了枚舉器接口的枚舉器類的實(shí)例,但其他的實(shí)現(xiàn)也是允許的。如果一個(gè)枚舉器類是由編譯器自動(dòng)生成的,則該類是直接或間接地嵌套在函數(shù)成員中的,具有私有的可訪問性,并且具有一個(gè)由編譯器保留使用的名字。

一個(gè)枚舉器對(duì)象可以實(shí)現(xiàn)上面所述之外的其它接口。

后面的幾節(jié)詳細(xì)地描述了由一個(gè)枚舉器對(duì)象所實(shí)現(xiàn)的IEnumerable和IEnumerable<T>接口中的MoveNext()、Current和Dispose()成員的確切行為。

注意,枚舉器對(duì)象不支持IEnumerator.Reset()方法。調(diào)用該方法會(huì)拋出System.NotSupporteException異常。

4.2.1 MoveNext()方法
枚舉器對(duì)象的MoveNext()方法封裝了迭代器塊的代碼。對(duì)MoveNext()方法的調(diào)用執(zhí)行了迭代器塊中的代碼,并為枚舉器對(duì)象的Current屬性設(shè)置一個(gè)適當(dāng)?shù)闹怠oveNext()方法完成得確切動(dòng)作取決于調(diào)用MoveNext()方法是枚舉器對(duì)象的狀態(tài):

如果枚舉器對(duì)象的狀態(tài)為before,調(diào)用MoveNext()方法:
將狀態(tài)設(shè)置為running。
將迭代器塊對(duì)象的參數(shù)(包括this)初始化為枚舉器對(duì)象初始化時(shí)所保存的變量值和實(shí)例值。
從執(zhí)行迭代器塊的開始執(zhí)行,直到被中斷(將在下面討論)。
如果枚舉器對(duì)象的狀態(tài)為running,則調(diào)用MoveNext()方法的結(jié)果未指定。
如果枚舉器對(duì)象的狀態(tài)為suspended,調(diào)用MoveNext()方法:
將狀態(tài)設(shè)置為running。
將所有局部變量和參數(shù)(包括this)恢復(fù)為迭代器塊執(zhí)行過(guò)程中最后一次掛起時(shí)所保存的值。注意這些變量所引用的對(duì)象的內(nèi)容在上一次MoveNext()后可能會(huì)發(fā)生改變。
從上一次執(zhí)行中斷所在的yield return語(yǔ)句繼續(xù)執(zhí)行迭代器塊,直到執(zhí)行再次被中斷(將在下面討論)。
如果枚舉器對(duì)象的狀態(tài)為after,調(diào)用MoveNext()方法將返回false。
當(dāng)MoveNext()方法執(zhí)行迭代器塊時(shí),執(zhí)行過(guò)程會(huì)通過(guò)四種途徑中斷:yield return語(yǔ)句、yield break語(yǔ)句、遇到迭代器塊的結(jié)尾以及迭代器塊中拋出了異常并被傳播到塊外。

當(dāng)遇到y(tǒng)ield return語(yǔ)句(見4.4)時(shí):
對(duì)語(yǔ)句中給定的表達(dá)式進(jìn)行求值,隱式轉(zhuǎn)換為生成類型,并賦給枚舉器對(duì)象的Current屬性。
掛起迭代器體的執(zhí)行過(guò)程。保存所有局部變量和參數(shù)(包括this)的值,以及這個(gè)yield return語(yǔ)句的位置。如果該yield return語(yǔ)句位于一個(gè)或多個(gè)try塊中,則與之相關(guān)聯(lián)的finally塊在此時(shí)還不會(huì)被執(zhí)行。
將枚舉器對(duì)象的狀態(tài)設(shè)置為suspended。
向MoveNext()方法的調(diào)用者返回true,表示迭代已經(jīng)成功地轉(zhuǎn)移到下一個(gè)值上。
當(dāng)遇到y(tǒng)ield break語(yǔ)句(見4.4)時(shí):
如果該yield break語(yǔ)句位于一個(gè)或多個(gè)try塊中,則執(zhí)行與之相關(guān)聯(lián)的finally塊。
將枚舉器對(duì)象的狀態(tài)設(shè)置為after。
向MoveNext()方法的調(diào)用者返回false,表示迭代完成。
當(dāng)遇到迭代器快的結(jié)尾時(shí):
將枚舉器對(duì)象的狀態(tài)設(shè)置為after。
向MoveNext()方法的調(diào)用者返回false,表示迭代完成。
當(dāng)?shù)骺靾?bào)出了一個(gè)異常,并傳播到塊外時(shí):
迭代器塊中適當(dāng)?shù)膄inally塊將被執(zhí)行。
將枚舉器對(duì)象的狀態(tài)設(shè)置為after。
將異常傳播給MoveNext()方法的調(diào)用者。
4.2.2 Current屬性
一個(gè)枚舉器對(duì)象的Current屬性受迭代器塊中的yield return語(yǔ)句的影響。

當(dāng)一個(gè)枚舉器對(duì)象處于suspended狀態(tài)時(shí),Current屬性的值由最后一次對(duì)MoveNext()方法的調(diào)用設(shè)置。當(dāng)一個(gè)枚舉器對(duì)象處于before、running或after狀態(tài)時(shí),訪問Current屬性的結(jié)果是未定義的。

如果一個(gè)迭代器塊的生成類型不是object,通過(guò)枚舉器對(duì)象實(shí)現(xiàn)的IEnumerable以及相應(yīng)的IEnumerator<T>對(duì)Current的訪問會(huì)將結(jié)果轉(zhuǎn)換為object。

4.2.3 Dispose()方法
Dispose()方法通過(guò)將枚舉器對(duì)象的狀態(tài)設(shè)置為after來(lái)清除迭代器。

如果枚舉器對(duì)象的狀態(tài)為before,調(diào)用Dispose()方法將其狀態(tài)設(shè)置為after。
如果枚舉器對(duì)象的狀態(tài)為running,調(diào)用Dispose()方法的結(jié)果是未定義的。
如果枚舉器對(duì)象的狀態(tài)為suspended,調(diào)用Dispose()方法:
將狀態(tài)設(shè)置為running。
執(zhí)行所有的finally塊,好像yield return語(yǔ)句是yield break語(yǔ)句一樣。如果這導(dǎo)致了異常被拋出并傳播到迭代器塊外,則將枚舉器對(duì)象的狀態(tài)設(shè)置為after并將異常傳播給Dispose()方法的調(diào)用者。
將狀態(tài)設(shè)置為after。
如果枚舉器對(duì)象的狀態(tài)為after,調(diào)用Dispose()方法沒有任何效果。
4.3 Enumerable對(duì)象
當(dāng)一個(gè)返回一個(gè)可枚舉接口類型的函數(shù)成員使用了迭代器塊時(shí),對(duì)該函數(shù)成員的調(diào)用不會(huì)立即執(zhí)行迭代器塊中的代碼,而是建立并返回一個(gè)可枚舉對(duì)象。該可枚舉對(duì)象有一個(gè)GetEnumerator()方法,能夠返回一個(gè)枚舉器對(duì)象。該枚舉器對(duì)象封裝了迭代器塊中指定的代碼,當(dāng)調(diào)用這個(gè)枚舉器對(duì)象的MoveNext()方法時(shí),會(huì)執(zhí)行迭代器塊中的代碼。一個(gè)可枚舉對(duì)象具有如下特征:

它實(shí)現(xiàn)了IEnumerable或IEnumerable<T>,這里T是迭代器塊的生成類型。
它用傳遞給函數(shù)成員的參數(shù)值(如果有的話)和實(shí)例值進(jìn)行初始化。
典型的可枚舉對(duì)象是由編譯器自動(dòng)生成的封裝了迭代器塊中的代碼并實(shí)現(xiàn)了可枚舉接口的可枚舉類的實(shí)例,但其他的實(shí)現(xiàn)也是允許的。如果一個(gè)可枚舉類是由編譯器自動(dòng)生成的,則該類是直接或間接地嵌套在函數(shù)成員中的,具有私有的可訪問性,并且具有一個(gè)由編譯器保留使用的名字。

一個(gè)可枚舉對(duì)象可以實(shí)現(xiàn)上述之外的其它接口。例如,一個(gè)可枚舉對(duì)象還可以實(shí)現(xiàn)IEnumerator和IEnumerator<T>,使得它既是可枚舉的又是一個(gè)枚舉器。這種情況下,當(dāng)可枚舉對(duì)象的GetEnumerator()方法第一次被調(diào)用時(shí),將返回可枚舉對(duì)象本身。以后對(duì)可枚舉對(duì)象的GetEnumerator()方法的調(diào)用(如果有的話),將返回可枚舉對(duì)象的一個(gè)拷貝。因此,每個(gè)被返回的枚舉器具有其自己的狀態(tài),并且一個(gè)枚舉器和其它枚舉器互不影響。

4.3.1 GetEnumerator()方法
一個(gè)可枚舉對(duì)象提供了對(duì)IEnumerator和IEnumberator<T>接口的GetEnumerator()方法的實(shí)現(xiàn)。兩個(gè)GetEnumerator()方法共享一個(gè)實(shí)現(xiàn),能夠獲取并返回一個(gè)有效的枚舉器對(duì)象。該枚舉器對(duì)象使用可枚舉對(duì)象被初始化時(shí)所保存的參數(shù)值和實(shí)例值進(jìn)行初始化,該枚舉器對(duì)象的功能如4.2節(jié)所描述。

4.4 yield語(yǔ)句
迭代器塊中的yield語(yǔ)句用于生成一個(gè)值,或發(fā)出一個(gè)迭代完成的信號(hào)。

embedded-statement:
...
yield-statement

yield-statement:
yield return expression ;
yield break ;

內(nèi)嵌語(yǔ)句:
...
yield語(yǔ)句

yield語(yǔ)句:
yield return 表達(dá)式 ;
yield break ;

為了保證和現(xiàn)有程序的兼容性,yield并不是一個(gè)保留字,只有當(dāng)一個(gè)return語(yǔ)句緊隨其后時(shí),yield語(yǔ)句才有這特殊的意義。其它情況下,yield語(yǔ)句可以用作標(biāo)識(shí)符。

yield語(yǔ)句的出現(xiàn)首很多限制,如下所描述:

如果一個(gè)yield語(yǔ)句出現(xiàn)在方法體、運(yùn)算符體或訪問器體之外,則會(huì)引起編譯錯(cuò)誤。
如果一個(gè)yield語(yǔ)句出現(xiàn)在匿名方法內(nèi)部,則會(huì)引起編譯錯(cuò)誤。
如果一個(gè)yield語(yǔ)句出現(xiàn)在finally或一個(gè)try塊內(nèi),則會(huì)引起編譯錯(cuò)誤。
如果一個(gè)yield語(yǔ)句出現(xiàn)在一個(gè)帶有catch語(yǔ)句的try塊內(nèi),則會(huì)引起編譯錯(cuò)誤。
下面的例子展示了一些yield語(yǔ)句的有效的和無(wú)效的用法。

delegate IEnumerable<int> D();

IEnumerator<int> GetEnumerator() {
try {
yield return 1; // 正確
yield break; // 正確
}
finally {
yield return 2; // 錯(cuò)誤,yield出現(xiàn)在finally塊中E
yield break; // 錯(cuò)誤,yield出現(xiàn)在finally塊中
}

try {
yield return 3; // 錯(cuò)誤,yield return語(yǔ)句出現(xiàn)在try...catch語(yǔ)句中
yield break; // 正確
}
catch {
yield return 4; // 錯(cuò)誤,yield return語(yǔ)句出現(xiàn)在try...catch語(yǔ)句中
yield break; // 正確
}

D d = delegate {
yield return 5; // 錯(cuò)誤,yield語(yǔ)句出現(xiàn)在匿名方法中
};
}

int MyMethod() {
yield return 1; // 錯(cuò)誤,迭代器塊具有錯(cuò)誤的返回值類型
}

從yield return語(yǔ)句中的表達(dá)式的類型到迭代器塊的生成類型(見4.1.3)必存在一個(gè)隱式轉(zhuǎn)換。

yield return語(yǔ)句依照下面的步驟執(zhí)行:

對(duì)語(yǔ)句中給定的表達(dá)式進(jìn)行求值,并隱式轉(zhuǎn)換為生成類型,然后賦給枚舉器對(duì)象的Current屬性。
掛起對(duì)迭代器塊的執(zhí)行。如果該yield return語(yǔ)句位于一個(gè)或多個(gè)try塊中,相應(yīng)的finally塊暫時(shí)不會(huì)被執(zhí)行。
MoveNext()方法向其調(diào)用者返回true,表示枚舉器對(duì)象成功地前進(jìn)到下一個(gè)值上。
對(duì)枚舉器對(duì)象的MoveNext()方法的下一次調(diào)用將從上一次掛起的地方恢復(fù)對(duì)迭代器塊的執(zhí)行。

yield break語(yǔ)句依照下面的步驟執(zhí)行:

如果yield break語(yǔ)句位于一個(gè)或多個(gè)帶有finally塊的try塊中,控制將被轉(zhuǎn)移到最里面的try塊對(duì)應(yīng)的finally塊中。當(dāng)控制流程遇到finally塊的結(jié)尾(如果能夠的話),控制將被轉(zhuǎn)移到外一層try塊對(duì)應(yīng)的finally塊中。這個(gè)過(guò)程持續(xù)到所有try語(yǔ)句對(duì)應(yīng)的finally塊都被執(zhí)行完。
將控制返回給迭代器塊的調(diào)用者。這可能從MoveNext()方法或Dispose()方法中返回。
由于一個(gè)yield break語(yǔ)句無(wú)條件地將控制轉(zhuǎn)移到其它地方,因此一個(gè)yield break的終點(diǎn)將永遠(yuǎn)不可達(dá)。

4.4.1 明確賦值
對(duì)于下面形式的yield return語(yǔ)句:

yield return expr ;

對(duì)于一個(gè)變量v,在expr的開始處和語(yǔ)句的開始處有同樣的明確賦值。
如果一個(gè)變量v在expr的結(jié)束處被明確賦值,則它是在語(yǔ)句的結(jié)尾被明確賦值的;否則,它未在語(yǔ)句的結(jié)尾被明確賦值。
4.5 實(shí)例
這一節(jié)將描述標(biāo)準(zhǔn)C#結(jié)構(gòu)中的迭代器可能的實(shí)現(xiàn)。這里描述的實(shí)現(xiàn)是基于和Microsoft C#編譯器相同的原則的,但決不是唯一可能的實(shí)現(xiàn)。

下面的Stack<T>類使用一個(gè)迭代器實(shí)現(xiàn)了它的GetEnumerator()方法。該迭代器按照從頂至底的順序枚舉了堆棧中的所有元素。

using System;
using System.Collections;
using System.Collections.Generic;

class Stack<T> : IEnumerable<T> {
T[] items;
int count;

public void Push(T item) {
if (items == null) {
items = new T[4];
}
else if (items.Length == count) {
T[] newItems = new T[count * 2];
Array.Copy(items, 0, newItems, 0, count);
items = newItems;
}
items[count++] = item;
}

public T Pop() {
T result = items[--count];
items[count] = T.default;
return result;
}

public IEnumerator<T> GetEnumerator() {
for(int i = count - 1; i >= 0; --i) yield items[i];
}
}

GetEnumerator()方法可以轉(zhuǎn)換為編譯器自動(dòng)生成的枚舉器類的實(shí)例,它封裝了迭代器塊中指定的代碼,如下所示:

class Stack<T> : IEnumerable<T> {
...
public IEnumerator<T> GetEnumerator() {
return new __Enumerator1(this);
}

class __Enumerator1 : IEnumerator<T>, IEnumerator {
int __state;
T __current;
Stack<T> __this;
int i;

public __Enumerator1(Stack<T> __this) {
this.__this = __this;
}

public T Current {
get { return __current; }
}

object IEnumerator.Current {
get { return __current; }
}

public bool MoveNext() {
switch (__state) {
case 1: goto __state1;
case 2: goto __state2;
}

i = __this.count - 1;

__loop:
if(i < 0) goto __state2;
__current = __this.items[i];
__state = 1;
return true;

__state1:
--i;
goto __loop;

__state2:
__state = 2;
return false;
}

public void Dispose() {
__state = 2;
}

void IEnumerator.Reset() {
throw new NotSupportedException();
}
}
}

上面的轉(zhuǎn)換中,迭代器塊中的代碼被轉(zhuǎn)換為狀態(tài)機(jī)并放在枚舉器類的MoveNext()方法中。此外,局部變量i被轉(zhuǎn)換為枚舉器對(duì)象的域,因此在對(duì)MoveNext()方法的調(diào)用過(guò)程中它將一直存在。

下面的例子打印了整數(shù)1至10的一個(gè)簡(jiǎn)單的乘法表。例子中的FromTo()方法返回了一個(gè)用迭代器實(shí)現(xiàn)的可枚舉對(duì)象。

using System;
using System.Collections.Generic;

class Test {
static IEnumerable<int> FromTo(int from, int to) {
while(from <= to) yield return from++;
}

static void Main() {
IEnumerable<int> e = FromTo(1, 10);

foreach(int x in e) {
foreach(int y in e) {
Console.Write("{0,3} ", x * y);
}
Console.WriteLine();
}
}
}

FromTo()方法可以被轉(zhuǎn)換為由編譯器自動(dòng)生成的可枚舉類的實(shí)例,它封裝了迭代器塊中的代碼,如下所示:

using System;
using System.Threading;
using System.Collections;
using System.Collections.Generic;

class Test {
...
static IEnumerable<int> FromTo(int from, int to) {
return new __Enumerable1(from, to);
}

class __Enumerable1 : IEnumerable<int>, IEnumerable, IEnumerator<int>, IEnumerator {
int __state;
int __current;
int __from;
int from;
int to;
int i;

public __Enumerable1(int __from, int to) {
this.__from = __from;
this.to = to;
}

public IEnumerator<int> GetEnumerator() {
__Enumerable1 result = this;
if(Interlocked.CompareExchange(ref __state, 1, 0) != 0) {
result = new __Enumerable1(__from, to);
result.__state = 1;
}
result.from = result.__from;
return result;
}

IEnumerator IEnumerable.GetEnumerator() {
return (IEnumerator)GetEnumerator();
}

public int Current {
get { return __current; }
}

object IEnumerator.Current {
get { return __current; }
}

public bool MoveNext() {
switch (__state) {
case 1:
if(from > to) goto case 2;
__current = from++;
__state = 1;
return true;

case 2:
__state = 2;
return false;

default:
throw new InvalidOperationException();
}
}

public void Dispose() {
__state = 2;
}

void IEnumerator.Reset() {
throw new NotSupportedException();
}
}
}

這個(gè)可枚舉類同時(shí)實(shí)現(xiàn)了可枚舉接口和枚舉器接口,因此它既是可枚舉的又是一個(gè)枚舉器。當(dāng)GetEnumerator()方法第一次被調(diào)用時(shí),將返回可枚舉對(duì)象本身。以后對(duì)GetEnumerator()方法的調(diào)用(如果有的話),將返回可枚舉對(duì)象的一個(gè)拷貝。因此返回的每一個(gè)枚舉器具有其自己的狀態(tài),一個(gè)枚舉器的改變不會(huì)影響到其它的枚舉器。Interlocked.CoompareExchange()方法可以用于確保線程安全。

from和to參數(shù)被轉(zhuǎn)換為可枚舉類的域。因?yàn)榈鲏K改變了from,因此引入了一個(gè)附加的__from域來(lái)保存每個(gè)枚舉器中的from的初始值。

當(dāng)__state是0時(shí),MoveNext()方法將跑出一個(gè)InvalidOperationException異常。這將保證不會(huì)發(fā)生沒有首先調(diào)用GetEnumerator()方法而直接將可枚舉對(duì)象用

溫馨提示:喜歡本站的話,請(qǐng)收藏一下本站!

本類教程下載

系統(tǒng)下載排行

網(wǎng)站地圖xml | 網(wǎng)站地圖html
主站蜘蛛池模板: 华容县| 辽宁省| 五河县| 鱼台县| 南岸区| 丽江市| 阜阳市| 泰州市| 双鸭山市| 常德市| 怀集县| 宜君县| 汝阳县| 汉川市| 新河县| 罗城| 固始县| 多伦县| 团风县| 德阳市| 河曲县| 安溪县| 紫阳县| 舒兰市| 永丰县| 揭东县| 清远市| 新蔡县| 华安县| 晋州市| 故城县| 清河县| 长春市| 赤水市| 纳雍县| 许昌市| 滨海县| 永登县| 诸暨市| 景泰县| 远安县|