日韩av黄I国产麻豆传媒I国产91av视频在线观看I日韩一区二区三区在线看I美女国产在线I麻豆视频国产在线观看I成人黄色短片

歡迎訪問 生活随笔!

生活随笔

當(dāng)前位置: 首頁 >

关于for和foreach,兼顾效率与安全

發(fā)布時(shí)間:2025/5/22 43 豆豆
生活随笔 收集整理的這篇文章主要介紹了 关于for和foreach,兼顾效率与安全 小編覺得挺不錯(cuò)的,現(xiàn)在分享給大家,幫大家做個(gè)參考.
對(duì)于數(shù)組的訪問,是應(yīng)該使用for的方式的,因?yàn)檫@樣性能更高。以下代碼是恰當(dāng)?shù)摹? Object[]?objArray?=?...;
int?objArrayLength?=?objArray.Length;
for?(int?i?=?0;?i?<?objArrayLength;?++i)
{
????
//?do?something ...
}


String?str?
=?...;
int?strLength?=?str.Length;
for?(int?i?=?0;?i?<?strLength;?++i)?
{
???
//?do?something ...
}

對(duì)ArrayList這樣的可使用下標(biāo)進(jìn)行隨機(jī)訪問的數(shù)據(jù)結(jié)構(gòu),使用下標(biāo)訪問,要比foreach的方式進(jìn)行順序訪問,速度要快一些。foreach這樣寫法,使用的過程產(chǎn)生一個(gè)額外的對(duì)象Enumerator,而且每次訪問需要更多的操作,降低性能。下面的兩種寫法編譯出的代碼是一樣的:
第一種寫法:
IList?list?=?new?ArrayList();
IEnumerator?iter?
=?list.GetEnumerator();
try
{
????
while?(iter.MoveNext())
????
{
????????Object?obj?
=?iter.Current;
????????
//do?something?...
????}

}

finally
{
????IDisposable?disposableObj?
=?iter?as?IDisposable;
????
if?(disposableObj?!=?null)
????
{
????????disposableObj.Dispose();
????}

}

第二種寫法: IList?list?=?new?ArrayList();
foreach?(Object?obj?in?list)
{
????
//do?something?...
}

對(duì)比這兩種寫法,第一種寫法非常羅嗦,所以C#引入了foreach的語法。通過觀察第一種寫法,foreach是通過GetEnumerator獲得一個(gè)IEnumerator對(duì)象,通過IEnumerator對(duì)象執(zhí)行MoveNext()方法和獲取Current屬性進(jìn)行遍歷的。

我們?cè)偻ㄟ^Reflector工具,查看mscorlib.dll中System.Collection.ArrayList的實(shí)現(xiàn): //為了簡單起見,我只列出ArrayList的Add、Clear、GetEnumerator的代碼
public?class?ArrayList
{
????
//這是一個(gè)版本標(biāo)識(shí),ArrayList對(duì)象,每做一個(gè)修改操作,_version都會(huì)加1
????private?int?_version;

????
public?virtual?int?Add(object?value)
????
{
????????
int?num1;
????????
if?(this._size?==?this._items.Length)
????????
{
????????????
this.EnsureCapacity((this._size?+?1));
????????}

????????
this._items[this._size]?=?value;
????????
++this._version;?//注意此處
????????this._size?=?((num1?=?this._size)?+?1);
????????
return?num1;
????}


????
public?virtual?void?Clear()
????
{
????????Array.Clear(
this._items,?0,?this._size);
????????
this._size?=?0;
????????
++this._version;?//注意此處
????}


????
//每次調(diào)用GetEnumerator方法,都會(huì)構(gòu)造一個(gè)FastArrayListEnumerator
????
//或者ArrayListEnumeratorSimple對(duì)象。
????public?virtual?IEnumerator?GetEnumerator()
????
{
????????
if?(base.GetType()?==?typeof(ArrayList))
????????
{
????????????
return?new?ArrayList.FastArrayListEnumerator(this);
????????}

????????
return?new?ArrayList.ArrayListEnumeratorSimple(this);
????}

}

通過上述代碼可以看到,ArrayList是通過_version成員變量作版本標(biāo)識(shí)的,每次執(zhí)行Add、Clear等修改ArrayList內(nèi)容的操作,都會(huì)將版本號(hào)加1,而每次調(diào)用GetEnumerator方法,都會(huì)構(gòu)造一個(gè)FastArrayListEnumerator或者ArrayListEnumeratorSimple對(duì)象。我們?cè)倏碏astArrayListEnumerator的實(shí)現(xiàn): class?FastArrayListEnumerator
{
????
private?int?version;

????
internal?FastArrayListEnumerator(ArrayList?list)
????
{
????????
this.list?=?list;
????????
this.index?=?-1;

????????
//獲取構(gòu)建FastArrayListEnumerator對(duì)象時(shí)ArrayList的版本號(hào)
????????this.version?=?list._version;?

????????
this.lastIndex?=?(list._size?-?1);
????}


????
public?bool?MoveNext()
????
{
????????
int?num1;

????????
//比較ArrayList當(dāng)前的版本號(hào),
????????
//是否和構(gòu)建FastArrayListEnumerator對(duì)象時(shí)的版本號(hào)一致
????????
//如果不一致,則拋出異常。
????????if?(this.version?!=?this.list._version)
????????
{
????????????
throw?new?InvalidOperationException(
????????????????Environment.GetResourceString(
"InvalidOperation_EnumFailedVersion")
????????????????);
????????}


????????
//... ...?
????}

}

FastArrayListEnumerator對(duì)象構(gòu)建時(shí),當(dāng)時(shí)時(shí)ArrayList的版本號(hào)。當(dāng)執(zhí)行MoveNext()操作時(shí),檢查ArrayList當(dāng)前的版本號(hào)是否和FastArrayListEnumerator對(duì)象構(gòu)建時(shí)的版本號(hào)一致,如果不一致就會(huì)拋出異常。

由于Enumerator中,做了版本檢查處理的工作,所以使用foreach是線程安全,而使用for則不時(shí)。為什么呢?如果在使用foreach遍歷對(duì)象的過程中,其他線程修改了List的內(nèi)容,例如添加或者刪除,就會(huì)出現(xiàn)不可知的錯(cuò)誤,而使用foreach則能夠正確拋出錯(cuò)誤信息。

綜上所述,結(jié)論如下:
使用for,更高效率。
使用foreach,更安全。

那么如何選擇呢?我的建議是,在一些全局的,多線程可以訪問的數(shù)據(jù)結(jié)構(gòu)對(duì)象,使用foreach。而對(duì)本地變量,則使用for,效率和安全兼顧!例如: public?void?F1(IList?globalList)
{
????IList?waitForDeleteList?
=?new?ArrayList();

????
//全局變量,使用foreach,保證線程
????foreach?(Object?item?in?globalList)
????
{

????????
if?(condition)
????????
{
????????????waitForDeleteList.Add(item);
????????}

????}


????
//本地變量使用for,保證效率
????int?waitForDeleteListCount?=?waitForDeleteList.Count;
????
for?(int?i?=?0;?i?<?waitForDeleteListCount;?++i)
????
{
????????globalList.Remove(waitForDeleteList[i]);
????}

}

以上建議,對(duì)于在Java環(huán)境下也使用,我閱讀過JDK 1.4的java.util.ArrayList的實(shí)現(xiàn),.NET Framework的實(shí)現(xiàn)和JDK的實(shí)現(xiàn),幾乎是一樣的,是否抄襲,見仁見智。上述的C#代碼在Java環(huán)境中應(yīng)為: public?void?f1(List?globalList)?{
????List?waitForDeleteList?
=?new?ArrayList();
????
//全局變量,使用Iterator遍歷,保證線程
????Iterator?iter?=?globalList.iterator();
????
while?(iter.hasNext())?{
????????Object?item?
=?iter.next();
????????
if?(condition)?{
????????????waitForDeleteList.add(item);
????????}

????}

????
????
//本地變量使用for,保證效率
????int?waitForDeleteListCount?=?waitForDeleteList.size();
????
for?(int?i?=?0;?i?<?waitForDeleteListCount;?++i)?{
????????globalList.remove(waitForDeleteList.
get(i));
????}

}


注意,以上代碼并不是做該項(xiàng)工作的最優(yōu)算法,如果需要更高的效率,修改如下:
C#版本
public?void?F1(IList?globalList)
{
????
bool?condition?=?true;
????IList?waitForDeleteList?
=?new?ArrayList();

????
//全局變量,使用foreach,保證線程
????int?itemIndex?=?0;
????
foreach?(Object?item?in?globalList)
????
{
????????
if?(condition)
????????
{
????????????waitForDeleteList.Add(index);
????????}

????????
++itemIndex;
????}


????
//本地變量使用for,保證效率
????int?waitForDeleteListCount?=?waitForDeleteList.Count;
????
for?(int?i?=?waitForDeleteListCount?-?1;?i?>=?0;?--i)
????
{
????????index?
=?(int)?waitForDeleteList[i];
????????globalList.RemoveAt(itemIndex);
????}

}

Java版本:
public?void?f1(List?globalList)?{
????List?waitForDeleteList?
=?new?ArrayList();
????
//全局變量,使用Iterator遍歷,保證線程
????Iterator?iter?=?globalList.iterator();
????
int?index?=?0;
????
while?(iter.hasNext())?{
????????Object?item?
=?iter.next();
????????
if?(condition)?{
????????????waitForDeleteList.add(
new?Integer(index));
????????}

????????
++index;
????}

????
????
//本地變量使用for,保證效率
????int?waitForDeleteListCount?=?waitForDeleteList.size();
????
for?(int?i?=?waitForDeleteListCount?-?1;?i?>=?0;?--i)?{
???????index?
=?((Integer)?waitForDeleteList.get(i)).intValue();
????????globalList.remove(index);
????}

}

轉(zhuǎn)載于:https://www.cnblogs.com/jobs/archive/2004/07/17/25218.html

總結(jié)

以上是生活随笔為你收集整理的关于for和foreach,兼顾效率与安全的全部內(nèi)容,希望文章能夠幫你解決所遇到的問題。

如果覺得生活随笔網(wǎng)站內(nèi)容還不錯(cuò),歡迎將生活随笔推薦給好友。