非泛型集合的集合问题

非泛型集合的使用实例

  假设我们创建了非泛型的System.Collections.ArrayList来保存数值(分配在栈上的)数据,查询ArrayList成员,就会发现它们所操作的是System.Object数据:

public class ArrayList:...
{
  ...
  public virtual int Add(object value);
  public virtual void Insert(int index,object value);
  public virtual void Remove(object obj);
  public virtual object this[int index] { get;set;}
}

  ArrayList所操作的是object,这表示数据分配在堆上,然而下面的代码不但可以通过编译,而且执行时也不会抛出错误:

static void WorkWithArrayList()
{
  //在传递给需要object的方法时,值类型会自动装箱
  ArrayList myInts = new ArrayList();
  myInts.Add(10);
  myInts.Add(20);
  myInts.Add(35);
}

  尽管把数字数据(值类型)直接传入要求object的方法,但运行时会自动将栈数据进行装箱。
然后,如果希望从ArrayList中获取项,则必须使用转换操作,将堆分配的对象拆箱成栈分配的整数。

static void WorkWithArrayList()
{
  //在传递给需要object的方法时,值类型会自动装箱
  ArrayList myInts = new ArrayList();
  myInts.Add(10);
  myInts.Add(20);
  myInts.Add(35);

  //当将object转换回栈数据时,会发生拆箱
  int i = (int)myInts[0];//注意,ArrayList的索引器返回System.Object,不是System.Int32;

  //由于WriteLine()要求object类型,因此再次发生装箱操作
  Console.WriteLine("Value of your int:{0}",i);
}

装箱/拆箱带来的问题

  装箱和拆箱带来的堆/栈内存转移会导致性能问题,并且也缺乏类型安全。

类型安全问题

  其中对于类型安全问题,因为拆箱必须回到合适的数据类型,如果拆箱为不正确的变量将抛出异常。为了确保安全,你需要将每个拆箱操作都包裹在try/catch逻辑中,这样工作量大并且也带来了性能问题。

static void SimpleBoxUnboxOperation()
{
  //创建一个ValueType(int)变量
  int myInt = 25;

  //将int装箱为object引用
  object boxedInt = myInt;

  //拆箱为错误的数据类型将触发运行时异常
  try //为保证类型安全,大量使用try/catch将导致性能问题
  {
      long unboxedInt = (long)boxedInt;
  }
  catch(InvalidCastException ex)
  {
      Console.WriteLine(ex.Message);
  }
}

性能问题

除了try/catch可能带来的性能问题,思考一下在装箱和拆箱一个整数时发生的步骤,具体如下:
1. 必须在托管堆上分配一个新对象
2. 基于栈数据的值必须被转移到新分配的内存位置
3. 在拆箱时,保存在堆对象中的值必须转移回栈
4. 堆上无用的对象(最后)会被回收

理想情况下,我们应该可以在没有任何性能问题的容器中操作栈数据,并且在获取数据时也不必使用try/catch作用域(这正是泛型所实现的)

参考《精通C#(第六版)》章节9.2

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值