TComboBox的Items属性赋值解析

一般情况下对象类型作为参数传递时,传递的类型为引用型。因此,当对传入的参数执行Free时,该对象将被从内存清除。那么所有对它的引用将失效

但最近在写TComboBox相关的赋值操作时却发现,TComboBox的Items属性为TStrings类型,但执行
combobox.items := stringlist;
之后free掉stringlist,发现TComboBox的Items并没有被free掉,而是保持了原来的数据。

因此,我们可以想到在TComboBox的Items赋值操作中有一个数据复制机制,而不是简单的将引用赋值给Items属性。

打开stdCtrls单元,找到TCustomCombo的Items定义位置(TComboBox继承自TCustomCombo,其Items属性在TCustomCombo实现),我们发现下面一条语句:

property Items: TStrings read FItems write SetItems;

嗯,果然有一个SetItems,我们一起来看一下这个函数的实现,真相大白:

procedure TCustomCombo.SetItems(const Value: TStrings);
begin
  if Assigned(FItems) then
    FItems.Assign(Value)
  else
    FItems := Value;
end;

SetItems函数使用了其父类TPersistent的Assign函数来实现数据赋值,而只有在FItems成员为nil时才会复制引用,那么TComboBox必定在创建之时创建了FItems成员

为了验证这点,因为TComboBox仅仅是将TCustomComboBox封装成标准的VCL控件,本身并没有代码实现,因此,我们找到了TComboBox的直接父类TCustomComboBox,在它的Create函数中有这么一句:

FItems := GetItemsClass.Create;

这里VCL使用了一个技巧(此技巧在VCL Framework中大量出现),用GetItemsClass返回类对象,然后用其创建对象。

由此我们可以看到,FItems确实是在TComboBox创建的时候被初始化了,因此,只要没有去显式的free它,Items属性的赋值操作均为数据复制。

到此也找到了上述看似奇怪的问题。

VCL Framework中使用了大量的技巧以保证其高度的灵活性和极高的执行效率,多多深入研究VCL的实现方法对我们的设计思想大有帮助。

标签:
文章分类 FK Coding

发表评论

电子邮件地址不会被公开。 必填项已用 * 标注

*

您可以使用这些 HTML 标签和属性: <a href="" title=""> <abbr title=""> <acronym title=""> <b> <blockquote cite=""> <cite> <code> <del datetime=""> <em> <i> <q cite=""> <strike> <strong>

点赞
如果您觉得很赞,我将非常乐意接受虚拟币的捐赠,以示您对我的肯定。

比特币钱包地址:
1PqpqA8FyH3NbfCrbcRd1YxQk3LEsSEYDV
莱特币钱包地址:
LRTdmovGGVEHCKWz7JdL9aiB7VZkuNycJf
站点勋章
网站统计