You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何在Delphi不同单元复用对象属性并延长其生命周期?

如何在Delphi多个窗体间复用TUser对象并延长其生命周期?

这个问题是Delphi跨窗体共享对象实例的典型场景,核心问题在于你当前的代码里Form1和Form2各自维护了独立的objUser变量:Form2里的objUser没有初始化就调用方法,自然触发访问违例;如果重新Create,那就是一个全新的TUser实例,和Form1里设置了ID的那个完全没关系,所以值会丢失。

下面给你几种实用的解决方案,你可以根据自己的项目场景选择:

方案1:使用全局变量共享实例

最简单的方式是把TUser的实例放在全局作用域里,让所有窗体都能访问到同一个对象。

步骤:

  1. 在clsUser_U单元的interface部分添加全局变量:
unit clsUser_U;
interface
type
  TUser = class(TObject)
    // 原有类代码不变
  end;
var
  g_GlobalUser: TUser; // 全局变量
implementation
// 原有实现代码不变
end.
  1. 在程序启动时创建这个全局实例,退出时销毁(修改你的项目DPR文件):
program YourProjectName;
uses
  Forms,
  clsUser_U in 'clsUser_U.pas',
  Form1_U in 'Form1_U.pas' {Form1},
  Form2_U in 'Form2_U.pas' {Form2};
{$R *.res}
begin
  Application.Initialize;
  Application.MainFormOnTaskbar := True;
  g_GlobalUser := TUser.Create; // 创建全局实例
  try
    Application.CreateForm(TForm1, Form1);
    Application.Run;
  finally
    g_GlobalUser.Free; // 程序退出时销毁,避免内存泄漏
  end;
end.
  1. 修改Form1和Form2的代码,直接使用全局变量:
  • Form1的FormShow方法:
procedure TForm1.FormShow(Sender: TObject);
begin
  g_GlobalUser.setUserID(2); // 直接用全局实例
end;
  • Form2的FormShow方法:
procedure TForm2.FormShow(Sender: TObject);
begin
  lbl1.Caption := IntToStr(g_GlobalUser.getUserID); // 直接读取全局实例的ID
end;

优缺点:实现简单,适合小型项目;但全局变量会增加代码耦合度,大型项目里不推荐过度使用。

方案2:通过窗体属性传递实例

如果不想用全局变量,可以在Form2里添加一个公共属性,让Form1在打开Form2时把自己的TUser实例传递过去。

步骤:

  1. 修改Form2的代码,添加公共属性:
unit Form2_U;
interface
uses
  // 原有uses不变
  clsUser_U;
type
  TForm2 = class(TForm)
    lbl1: TLabel;
    procedure FormShow(Sender: TObject);
  private
    objUser : TUser ;
  public
    property UserInstance: TUser read objUser write objUser; // 新增公共属性
  end;
var
  Form2: TForm2;
implementation
// 原有实现不变
end.
  1. 修改Form1打开Form2的代码,传递实例:
procedure TForm1.btnNextFormClick(Sender: TObject);
begin
  Form2.UserInstance := objUser; // 把Form1的objUser传递给Form2
  Form2.ShowModal ;
end;
  1. Form2的FormShow方法保持原有代码即可,现在objUser已经被Form1赋值为正确的实例了。

优缺点:耦合度低,更灵活,适合需要传递不同实例的场景;需要手动管理实例的创建和销毁(比如Form1要负责在合适的时机Free掉objUser)。

方案3:给TUser实现单例模式

如果你的TUser对象在整个程序里只需要一个实例,可以用单例模式,让类自己维护唯一实例,所有窗体都通过统一入口获取这个实例。

步骤:

  1. 修改TUser类,添加单例逻辑:
unit clsUser_U;
interface
type
  TUser = class(TObject)
  private
    FUserID : integer ;
    class var FInstance: TUser; // 静态变量保存唯一实例
    constructor Create; reintroduce; // 重新定义构造函数为私有,禁止外部直接Create
  public
    class function GetInstance: TUser; static; // 获取实例的入口
    class procedure ReleaseInstance; static; // 释放实例
    procedure setUserID(iID : integer) ;
    Function getUserID : Integer ;
  end;
implementation
{ TUser }
constructor TUser.Create;
begin
  inherited;
  FUserID := 0; // 初始化默认值
end;

class function TUser.GetInstance: TUser;
begin
  if FInstance = nil then
    FInstance := TUser.Create;
  Result := FInstance;
end;

class procedure TUser.ReleaseInstance;
begin
  FInstance.Free;
  FInstance := nil;
end;

// 原有getUserID和setUserID代码不变
end.
  1. 修改Form1和Form2的代码,使用单例实例:
  • Form1的FormShow方法:
procedure TForm1.FormShow(Sender: TObject);
begin
  TUser.GetInstance.setUserID(2); // 获取单例实例并设置ID
end;
  • Form2的FormShow方法:
procedure TForm2.FormShow(Sender: TObject);
begin
  lbl1.Caption := IntToStr(TUser.GetInstance.getUserID); // 获取单例实例读取ID
end;
  1. 在程序退出时释放单例(修改DPR文件):
program YourProjectName;
// 原有uses不变
begin
  Application.Initialize;
  Application.MainFormOnTaskbar := True;
  try
    Application.CreateForm(TForm1, Form1);
    Application.Run;
  finally
    TUser.ReleaseInstance; // 释放单例实例
  end;
end.

优缺点:保证全局唯一实例,访问方便;但单例模式会增加类的复杂度,且如果使用不当可能导致内存泄漏或线程安全问题(如果是多线程项目需要额外处理同步)。


内容的提问来源于stack exchange,提问作者Stefan Oberholzer

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.05.13 08:34:02