我有两个单元,每个单元中有一个 class,它们需要彼此才能发挥作用。如何避免循环引用?
I have two units and a class in each unit that need each other to function. How do I avoid a circular reference?
我有 2 个 类、ClassA
和 ClassB
,每个都在自己独立的单元中,UnitA
和 UnitB
。
UnitA
使用 UnitB
。这允许 ClassA
调用 ClassB
的构造函数。然而,部分 ClassB's
功能需要使用 ClassA's
方法。我不能让 UnitB
使用 UnitA
,否则会导致循环引用。我有什么选择可以让 ClassB
从 UnitB
访问 ClassA's
方法?
这在很大程度上取决于两个 classes 需要如何相互使用。如果一个 class 在实现中使用了另一个,而不是接口,那么您可以将 uses 子句中的该单元从 interface
部分向下移动到 implementation
部分。
这两种方法都可行:
UnitA;
interface
uses
Classes, UnitB;
type
TClassA = class(TObject)
end;
...
.
UnitB;
interface
uses
Classes;
type
TClassB = class(TObject)
end;
implementation
uses
UnitA;
...
然而,如果你的两个 classes 的接口相互依赖,那么你别无选择,只能将两个 classes 放在同一个单元中(并使用前向声明)。
UnitA;
interface
uses
Classes;
type
TClassA = class;
TClassB = class;
TClassA = class(TObject)
end;
TClassB = class(TObject)
end;
...
在极少数情况下,您甚至可以将整个 class 定义向下移动到 implementation
。如果您需要在其他地方实际使用 class,那将没有用。
UnitB;
interface
implementation
uses
Classes, UnitA;
type
TClassB = class(TObject)
end;
...
根据复杂性,将共同共享的代码放在一个单独的单元中也是常见的做法。例如常量、记录数组类型、全局变量等。这个公共单元不得使用任何其他这些单元。
为了稍微扩展之前的答案,另一种可能性(虽然肯定不太可读)是指一个祖先,它们都可以访问(在极端情况下是 TObject),然后在实现阶段进行转换。所以
interface
TClassA = class
...
fRefToClassB : TObject; // internal ref
...
procedure UsingBRef( pVar : TObject );
...
end;
implementation
procedure TClassA.UsingClassB
begin
with fRefToClass as TClassB do
...
end;
procedure TClassB.UsingBRef( pVar : TObject );
begin
with pVar as TClassB do
...
end;
显然,同一个主题有很多变体,您实施的会比这更好。我要再次强调以前的解决方案更好,但是当其他所有方法都失败时,这提供了一个出路。
如果您有 Class 和 Class B,并且都使用 ClassA 中的方法,那么您可能希望将这些方法从 ClassA 重构到它们的单元中(如果您愿意,还可以 class)。
我有 2 个 类、ClassA
和 ClassB
,每个都在自己独立的单元中,UnitA
和 UnitB
。
UnitA
使用 UnitB
。这允许 ClassA
调用 ClassB
的构造函数。然而,部分 ClassB's
功能需要使用 ClassA's
方法。我不能让 UnitB
使用 UnitA
,否则会导致循环引用。我有什么选择可以让 ClassB
从 UnitB
访问 ClassA's
方法?
这在很大程度上取决于两个 classes 需要如何相互使用。如果一个 class 在实现中使用了另一个,而不是接口,那么您可以将 uses 子句中的该单元从 interface
部分向下移动到 implementation
部分。
这两种方法都可行:
UnitA;
interface
uses
Classes, UnitB;
type
TClassA = class(TObject)
end;
...
.
UnitB;
interface
uses
Classes;
type
TClassB = class(TObject)
end;
implementation
uses
UnitA;
...
然而,如果你的两个 classes 的接口相互依赖,那么你别无选择,只能将两个 classes 放在同一个单元中(并使用前向声明)。
UnitA;
interface
uses
Classes;
type
TClassA = class;
TClassB = class;
TClassA = class(TObject)
end;
TClassB = class(TObject)
end;
...
在极少数情况下,您甚至可以将整个 class 定义向下移动到 implementation
。如果您需要在其他地方实际使用 class,那将没有用。
UnitB;
interface
implementation
uses
Classes, UnitA;
type
TClassB = class(TObject)
end;
...
根据复杂性,将共同共享的代码放在一个单独的单元中也是常见的做法。例如常量、记录数组类型、全局变量等。这个公共单元不得使用任何其他这些单元。
为了稍微扩展之前的答案,另一种可能性(虽然肯定不太可读)是指一个祖先,它们都可以访问(在极端情况下是 TObject),然后在实现阶段进行转换。所以
interface
TClassA = class
...
fRefToClassB : TObject; // internal ref
...
procedure UsingBRef( pVar : TObject );
...
end;
implementation
procedure TClassA.UsingClassB
begin
with fRefToClass as TClassB do
...
end;
procedure TClassB.UsingBRef( pVar : TObject );
begin
with pVar as TClassB do
...
end;
显然,同一个主题有很多变体,您实施的会比这更好。我要再次强调以前的解决方案更好,但是当其他所有方法都失败时,这提供了一个出路。
如果您有 Class 和 Class B,并且都使用 ClassA 中的方法,那么您可能希望将这些方法从 ClassA 重构到它们的单元中(如果您愿意,还可以 class)。