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

Delphi中如何简化多层对象Assigned()链式空检查?

简化Delphi深层对象链式空检查的方案

首先得明确:你尝试直接写 if Assigned(ASomeObj.Session.UserInfo.SomeFactsList) then 是不可行的——只要中间任何一个对象(比如ASomeObj、Session、UserInfo)是nil,访问其属性时会直接触发访问违规(AV)导致程序崩溃,所以必须逐层验证每个环节的对象是否存在。

下面给你几个实用的简化方案,兼顾代码简洁性和可读性:

1. 利用Delphi 11+的空安全特性(最推荐)

从Delphi 11 Alexandria开始,官方引入了类似C#的?.空传播操作符,完美解决这个问题!你可以直接写出和C#几乎一样的代码:

if Assigned(ASomeObj?.Session?.UserInfo?.SomeFactsList) then
begin
  // 执行操作
end;

或者更简洁的判断nil:

if ASomeObj?.Session?.UserInfo?.SomeFactsList <> nil then
begin
  // 执行操作
end;

这个语法会自动逐层检查每个对象是否为nil,只要某一层是nil,整个表达式就会返回nil,不会触发AV,代码清晰到一眼就能看懂。

2. 自定义链式检查辅助函数(适配旧版本Delphi)

如果你的项目还在用Delphi 11以下的版本,可以写一个通用的辅助函数来封装逐层检查逻辑:

function ChainAssigned(const AStartObj: TObject; const ASelectors: array of TFunc<TObject, TObject>): Boolean;
var
  CurrentObj: TObject;
  Selector: TFunc<TObject, TObject>;
begin
  CurrentObj := AStartObj;
  Result := Assigned(CurrentObj);
  if not Result then Exit;

  // 遍历每个选择器,逐层检查对象
  for Selector in ASelectors do
  begin
    CurrentObj := Selector(CurrentObj);
    Result := Assigned(CurrentObj);
    if not Result then Break;
  end;
end;

调用的时候,用匿名方法指定每层的属性访问:

if ChainAssigned(ASomeObj, 
  [function(O: TObject): TObject begin Result := TSomeObj(O).Session; end,
   function(O: TObject): TObject begin Result := TSession(O).UserInfo; end,
   function(O: TObject): TObject begin Result := TUserInfo(O).SomeFactsList; end]) then
begin
  // 执行操作
end;

虽然比?.多写一点,但比原来一长串Assigned()嵌套要整洁,而且这个函数可以在整个项目里复用。

3. 封装检查逻辑到类方法(提升可读性)

如果这些对象是你自己定义的业务类,最好的做法是把检查逻辑封装到各自的类中,让代码更符合面向对象的单一职责原则:

// 在TSomeObj类中添加方法
function TSomeObj.HasValidSomeFactsList: Boolean;
begin
  Result := Assigned(Session) and Session.HasValidUserInfo;
end;

// 在TSession类中添加方法
function TSession.HasValidUserInfo: Boolean;
begin
  Result := Assigned(UserInfo) and UserInfo.HasValidSomeFactsList;
end;

// 在TUserInfo类中添加方法
function TUserInfo.HasValidSomeFactsList: Boolean;
begin
  Result := Assigned(SomeFactsList);
end;

之后主逻辑里的检查就变得异常简洁:

if Assigned(ASomeObj) and ASomeObj.HasValidSomeFactsList then
begin
  // 执行操作
end;

这种方式不仅简化了主代码,还把检查逻辑分散到各个类中,后续维护时如果对象结构变化,只需要修改对应类的检查方法即可。

额外的可读性建议

  • 不管用哪种方案,尽量把长检查逻辑从主业务代码中抽离出来,让主逻辑专注于业务操作;
  • 如果是临时的简单检查,也可以把逐层检查拆成多行对齐,比如:
    // 检查所有中间对象是否存在
    if Assigned(ASomeObj) 
       and Assigned(ASomeObj.Session) 
       and Assigned(ASomeObj.Session.UserInfo) 
       and Assigned(ASomeObj.Session.UserInfo.SomeFactsList) then
    begin
      // 执行操作
    end;
    
    换行对齐后,可读性也会比一行到底好很多。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.05.08 08:17:31