这是我最近的最后一篇关于.Net技术的随笔了,一方面把这个集合的实现写一下,另一方面也写一些关于.Net想法与总结,以后就很少在这里更新随笔了。
首先,我并不太在意是用1.1还是2.0或者3.5版本的.Net Framework,因为最后编译成IL语言后,没有什么区别。太多的改变只是CS编译器上的修改,让C#的功能强大了一些,让语言更简洁,也让开发更快了。我不想说太多的细节,据我所了解,C#2.0的一些改进都可以用1.1做一些小的技巧来实现。(不要让这些技巧成了MS的专利)
一个重大的改进就是强类型的集合。1.1里的通用集合类型ArrayList可以说是万能的,然而带来的后果就是效率问题。.Net性能的开销很多就是在Boxing和Unboxing,以及类型转换上。然而这些,有很多人不明白,在自己的代码里写了N多的Boxing和Unboxing还不知道,然后就说.Net效率低下。其实效率问题90%是程序员自己的问题。这个就不多说了。
2.0的泛型对集合中元素的数据类型做了检测,这样,就省去了类型转化的开销。而且,对于值类型的集合,它也不再是封装成Object以后再放到集合里,这样就省去了Boxing和Unboxing的开销。可以说是一个不小的改进。这里我给出一个1.1下Int32集合的两种写法,比较一下就会让很多人明白一些关于性能与效率的问题了。
这是MSDN里的一段示例代码,告诉我们如何自己写一个强类型的集合,这里以int32为例:
[Serializable]
public class Int32Collection : CollectionBase

{
public Int32 this[ int index ]

{
get

{
return( (Int32) List[index] );
}
set

{
List[index] = value;
}
}

public int Add( Int32 value )

{
return( List.Add( value ) );
}

public int IndexOf( Int32 value )

{
return( List.IndexOf( value ) );
}

public void Insert( int index, Int32 value )

{
List.Insert( index, value );
}

public void Remove( Int32 value )

{
List.Remove( value );
}

public bool Contains( Int32 value )

{
// If value is not of type Int32, this will return false.
return( List.Contains( value ) );
}

protected override void OnInsert( int index, Object value )

{
if ( value.GetType() != Type.GetType("System.Int32") )
throw new ArgumentException( "value must be of type Int32.", "value" );
}

protected override void OnRemove( int index, Object value )

{
if ( value.GetType() != Type.GetType("System.Int32") )
throw new ArgumentException( "value must be of type Int32.", "value" );
}

protected override void OnSet( int index, Object oldValue, Object newValue )

{
if ( newValue.GetType() != Type.GetType("System.Int32") )
throw new ArgumentException( "newValue must be of type Int32.", "newValue" );
}

protected override void OnValidate( Object value )

{
if ( value.GetType() != Type.GetType("System.Int32") )
throw new ArgumentException( "value must be of type Int32." );
}
}

这是通用的,以致于我们可以写一个模板:

public class NewCollection#region public class NewCollection

/**//*Descrition: */
[Serializable]
public class NewCollection : CollectionBase


{
//Fields
//Properties
public __SomeOjbect__ this[int i_Index]

{

get
{ return this.InnerList[i_Index] as __SomeOjbect__; }

set
{ this.InnerList[i_Index] = value; }
}
//ctor

public NewCollection()
{}
//Methods
public int Add(__SomeOjbect__ i_Object)

{
return this.InnerList.Add(i_Object);
}
public void Remove(__SomeOjbect__ i_Obj)

{
this.InnerList.Remove(i_Obj);
}
}
#endregion确实,我在自己的项目中经常这样用,特别是那个集合模板。然而它的几个缺点就如我前面说的。其实我们可以手动的改进一下,省掉Boxing和Unboxing以及类型转化。
这里我又写了一个简单的Int32Collection类,它就省掉Boxing和Unboxing以及类型转化:
# if Int32CollectionEx

public class Int32CollectionEx
#region public class Int32CollectionEx
[Serializable]
public class Int32Collection : IEnumerable

{
private int[] _InnerArray;
private int _Length;
private int _Capability;
private object _SycObject;
//
public int Length

{

get
{return this._Length;}
}
public int Count

{

get
{return this._Length;}
}
public int Capability

{

get
{return this._Capability;}
}
public int this[ int index ]

{
get

{
if(index<0||index>=this._Length)

{
throw new IndexOutOfRangeException();
}
return this._InnerArray[index];
}
set

{
if(index<0||index>=this._Length)

{
throw new IndexOutOfRangeException();
}
this._InnerArray[index] = value;
}
}
//
public Int32Collection(int i_Capability)

{
this._InnerArray = new int[i_Capability];
this._Capability = i_Capability;
this._Length = 0;
this._SycObject = new object();
}

public Int32Collection() : this(6)

{
}
//
public int Add(int i_Value)

{
lock(this._SycObject)

{
this.CheckCapability();
this._InnerArray[_Length] = i_Value;
this._Length ++;
}
return this._Length;
}

public void Remove(int i_Value)

{
lock(this._SycObject)

{
int i_Index = this.Find(i_Value);
if(i_Index>=0)

{
this.MoveValues_Front(i_Index);
}
this._Length--;
}
}

public void Insert(int i_Index, int i_Value)

{
if(i_Index<0||i_Index>this._Length)

{
throw new IndexOutOfRangeException();
}
lock(this._SycObject)

{
this.CheckCapability();
this.MoveValues_Back(i_Index);
this._InnerArray[i_Index] = i_Value;
this._Length ++;
}
}

private void MoveValues_Front(int i_StartIndex)

{
// if(i_StartIndex<0||i_StartIndex>this._Length)
// {
// throw new IndexOutOfRangeException();
// }
for(int i=i_StartIndex+1; i<this._Length;i++)

{
this._InnerArray[i-1] = this._InnerArray[i];
}
}

private void MoveValues_Back(int i_StartIndex)

{
// if(i_StartIndex<0||i_StartIndex>this._Length)
// {
// throw new IndexOutOfRangeException();
// }
for(int i=this._Length;i>i_StartIndex;i--)

{
this._InnerArray[i] = this._InnerArray[i-1];
}
}

public int Find(int i_Value)

{
for(int i=0; i<this._Length;i++)

{
if(this._InnerArray[i]==i_Value) return i;
}
return -1;
}

public int Find(int i_StartIndex,int i_Value)

{
if(i_StartIndex<0||i_StartIndex>this._Length)

{
throw new IndexOutOfRangeException();
}
for(int i=i_StartIndex; i<this._Length;i++)

{
if(this._InnerArray[i]==i_Value) return i;
}
return -1;
}

public int IndexOf(int i_Value)

{
return this.Find(i_Value);
}

public bool Contains(int i_Value)

{
if(this.Find(i_Value)>0) return true;
else return false;
}

//
public void Clear()

{
lock(this._SycObject)

{
this._Length = 0;
}
}
//
public void Sort()

{
for(int i = 0; i<this._Length;i++)

{
for(int j=i;j<this._Length;j++)

{
if(this._InnerArray[i]<this._InnerArray[j])

{
int m_Temp = this._InnerArray[i];
this._InnerArray[i] = this._InnerArray[j];
this._InnerArray[j] = this._InnerArray[i];
}
}
}
}
//
private void CheckCapability()

{
if(this._Length>=this._Capability-1)

{
int[] m_NewArray = new int[this._Capability*2];
this._Capability*=2;
for(int i = 0; i<this._Length;i++)

{
m_NewArray[i] = this._InnerArray[i];
}
this._InnerArray = m_NewArray;
}
}
//

IEnumerable Members#region IEnumerable Members
public Int32Enumerator GetEnumerator()

{
// TODO: Add Int32CollectionEx.GetEnumerator implementation
return new Int32Enumerator(this);
}
IEnumerator IEnumerable.GetEnumerator()

{
// TODO: Add Int32CollectionEx.GetEnumerator implementation
return new Int32Enumerator(this);
}
#endregion
}
#endregion
# endif


public class Int32Enumerator#region public class Int32Enumerator

/**//*Descrition: */
public class Int32Enumerator:IEnumerator

{
//Fields

//Properties
int _EnumeratorCount = -1;
Int32Collection _Collection;
int _Length

{

get
{return this._Collection.Length;}
}

//ctor
internal Int32Enumerator(Int32Collection i_Collection)

{
this._EnumeratorCount = i_Collection.Length;
this._Collection = i_Collection;
}

//Methods


IEnumerator Members#region IEnumerator Members
private int _Indicator = -1;

public void Reset()

{
// TODO: Add Int32CollectionEx.Reset implementation
if(this._EnumeratorCount != this._Length)

{
throw new InvalidOperationException("Collection has been changed while using the Enumerator.");
}
this._Indicator = -1;
}

public int Current

{
get

{
// TODO: Add Int32CollectionEx.Current getter implementation
return this._Collection[this._Indicator];
}
}

object IEnumerator.Current

{
get

{
// TODO: Add Int32CollectionEx.Current getter implementation
return this._Collection[this._Indicator];
}
}

public bool MoveNext()

{
// TODO: Add Int32CollectionEx.MoveNext implementation
if(this._EnumeratorCount != this._Length)

{
throw new InvalidOperationException("Collection has been changed while using the Enumerator.");
}
if(this._Indicator<this._Length-1)

{
this._Indicator++;
return true;
}
else

{
return false;
}
}

#endregion
}
#endregion这些代码算是学习一下吧,在2.0里就有了很大的改进,不用我们再花大力气来做这些事情了,而且这是机械式的代码。谁也不想为了一个集合的效率要写这么多代码,而且简单的几行也可以实现同样的功能时,很多人就选择了前者。(把这样的工作交给编译器来做确实是很明智的事。)
选哪方法并没有太大关系,在我的测试中,发现它们的性能开销在一般的应用中, 人根本感觉不到。然而,我觉得做为一个.Net开发人员,特别是注意细节的开发人员,应该时刻注意这些问题,不至于自己写出大量的低效率代码还不知道。
好了,这个讨论就这些!