【问题标题】:To copy from one object to another, can I assign the variables directly, or must I assign their properties individually?要从一个对象复制到另一个对象,我可以直接分配变量,还是必须单独分配它们的属性?
【发布时间】:2026-02-13 04:25:04
【问题描述】:

我想澄清一个疑问。在我当前的项目中,我发现有两个 TClientDataSet 组件。并将一个客户端数据集的属性和事件处理程序分配给另一个客户端数据集,如下所示:

  cds2.AfterApplyUpdates := cds1.AfterApplyUpdates;
  cds2.AfterCancel       := cds1.AfterCancel;
  cds2.AfterClose        := cds1.AfterClose;

还有

  cds2.CommandText       := cds1.CommandText;
  cds2.AutoCalcFields    := cds1.AutoCalcFields;
  cds2.DisableStringTrim := cds1.DisableStringTrim;

是否需要上述事件处理程序和属性的分配?

如果我们只是将一个客户端数据集分配给另一个,如下所示,这还不够吗?

  cds2 := cds1;

【问题讨论】:

  • 值得一提的是,从TPersistent派生的类可以实现Assign方法,它们可以复制某些属性的值,实现对象的深拷贝,或者提供分配对象的能力不同类别的。不幸的是,TClientDataSet 没有实现它。

标签: delphi


【解决方案1】:

Delphi 类是引用类型。这意味着当您定义一个类型为类的变量时,您实际上拥有的是对该对象的引用或指针。这使得赋值运算符:= 的含义是引用赋值而不是值赋值。

假设你有以下声明:

var
  o1, o2: TObject;
....
o1 := TObject.Create;
o2 := o1;

此时,您已经创建了一个对象,o1o2 都引用或指向同一个对象。您通过o1 引用所做的任何更改也可以通过o2 引用看到,因为只有一个对象或实例。

因此,在您的场景中,您有 cds1cds2,大概是指不同的实例。这意味着

cds2.CommandText := cds1.CommandText;

cds1.CommandText 的值复制到cds2.CommandText

这和

完全不同
cds2 := cds1;

复制引用,导致您丢失cds2 引用的单独对象。

在此处找到有关引用类型和值类型的更多讨论:Why should we use classes rather than records, or vice versa?

总而言之,您提出的两个选项做了非常不同的事情。您当前使用的复制属性值的代码可能有效。在这种情况下,您对复制参考的建议更改肯定不会达到您想要的效果。

【讨论】:

    【解决方案2】:

    首先:所有组件事件实际上只是引用事件方法的属性,然后将其用作事件处理程序。因此,当您将一个事件评估为

    cds2.AfterApplyUpdates := cds1.AfterApplyUpdates;
    

    您只是将引用分配给相同的方法。 对于事件,这是非常常用的,以避免多次编写相同的代码。

    第二点:当您使用

    将一个对象变量分配给另一个对象变量时,David 已经很伤心了
    cds2 := cds1;
    

    您只是将对象实例的相同引用分配给另一个变量。您没有复制对象的任何实际数据。

    第三点:即使您要求的内容会起作用,我怀疑您是否会想要使用它。为什么?因为这样做你会得到两个 TClientDataSet,它们将访问同一个数据库。拥有这些只是点睛之笔。

    【讨论】:

    • 有很多理由让两个 TDataSet 访问同一个数据库。事实上,他们创建了一个method to do so。我经常有两个指向相同数据的 TClientDataSet 实例(例如,一个用于更新,一个用于查找)。
    • 是的 - 我很想建议在 OP 消化了 David 所说的话之后,他应该看看 CloneCursor() 看看是否有更优雅的解决方案来满足他的实际需求。
    • @SilverWarior:正如你所说,cds2.AfterApplyUpdates := cds1.AfterApplyUpdates;您只是分配对相同方法的引用。对于事件,这是非常常用的,以避免多次编写相同的代码。这意味着如果 cds1 的处理程序上方的事件发生代码更改,那也会影响 cds2 的偶数处理程序,对吗?因为,cds2 事件处理程序有 cds1 事件处理程序的引用。
    • 是的,如果您确实更改了事件处理程序方法的代码,代码更改将影响两个组件,因为在这种情况下它们都使用相同的方法。
    • 有人在前面提到过,听起来你会从学习对象的“深拷贝”与“浅拷贝”中受益。这几乎与任何 OOP 语言相关,但特别是 Delphi 和 C++,您可以通过值(在对象的情况下为引用)和通过引用(通过显式分配指针)进行分配。更令人困惑的是,C++ 同时支持“引用”和“指针”。它还有一种构造函数,通常称为“复制构造函数”,而 Delphi 没有。这样可以确保当您将一个 obj“分配”给另一个 obj 时,您会复制正确的内容。
    最近更新 更多