1

我想将一个方法标记为过时,但 Delphi 5 没有这样的功能。

举个例子,这里是一个虚构的方法,它已被弃用和新的首选形式:

procedure TStormPeaksQuest.BlowHodirsHorn; overload; //obsolete
procedure TStormPeaksQuest.BlowHodirsHorn(UseProtection: Boolean); overload;

注意:对于这个假设的例子,我们假设使用无参数版本是非常糟糕的。不“使用保护”存在问题 - 没有好的解决方案。没有人喜欢不得不使用保护,但没有人愿意使用保护。所以我们让调用者在吹霍迪尔的喇叭时决定他们是否要使用保护。如果我们默认无参数版本继续使用保护:

procedure TStormPeaksQuest.BlowHodirsHorn;
begin
    BlowHodirsHorn(False); //No protection. Bad!
end;

那么开发人员就有各种讨厌的东西的风险。如果我们强制无参数版本使用保护:

procedure TStormPeaksQuest.BlowHodirsHorn;
begin
    BlowHodirsHorn(True); //Use protection; crash if there isn't any
end;

如果开发商没有得到任何保护,或者没有任何保护,那么就有可能出现问题。

现在我可以重命名过时的方法:

procedure TStormPeaksQuest.BlowHodirsHorn_Deprecatedd; overload; //obsolete
procedure TStormPeaksQuest.BlowHodirsHorn(UseProtection: Boolean); overload;

但这会导致编译错误,人们会嘲笑我(我真的不想听到他们的抱怨)。我希望他们得到一个唠叨,而不是一个实际的错误。

我想过添加一个断言:

procedure TStormPeaksQuest.BlowHodirsHorn; //obsolete
begin
   Assert(false, 'TStormPeaksQuest.BlowHodirsHorn is deprecated. Use BlowHodirsHorn(Boolean)');

   ...
end;

但我不能保证开发人员不会在没有断言的情况下发布版本,从而给客户造成严重的崩溃。

如果开发人员正在调试,我考虑只使用抛出一个断言:

procedure TStormPeaksQuest.BlowHodirsHorn; //obsolete
begin
   if DebugHook > 0 then
      Assert(false, 'TStormPeaksQuest.BlowHodirsHorn is deprecated. Use BlowHodirsHorn(Boolean)');

   ...
end;

但我真的不想造成崩溃。

如果它们在调试器中,我想显示一个 MessageDlg(这是我过去做过的一种技术):

procedure TStormPeaksQuest.BlowHodirsHorn; //obsolete
begin
   if DebugHook > 0 then
        MessageDlg('TStormPeaksQuest.BlowHodirsHorn is deprecated. Use BlowHodirsHorn(Boolean)', mtWarning, [mbOk], 0);

   ...
end;

但这仍然太具有破坏性。并且它导致了代码卡在显示模式对话框的问题,但对话框并不明显可见。

我希望有某种警告信息会坐在那里唠叨他们 - 直到他们挖出他们的眼睛并最终改变他们的代码。

我想也许如果我添加了一个未使用的变量:

procedure TStormPeaksQuest.BlowHodirsHorn; //obsolete
var
   ThisMethodIsObsolete: Boolean;
begin
   ...
end;

我希望这只会在有人引用代码时引起提示。但是即使您不调用实际使用过时的方法,Delphi 也会显示提示。

谁能想到别的?

4

7 回答 7

5

像这样的东西怎么样

procedure TStormPeaksQuest.BlowHaldirsHorn; //obsolete
begin
  if DebugHook > 0 then asm int 3 end;  
  // This method is Obsolete!  Use XXXXX instead.
  Abort; // Optional, makes method useless  
  // old code here . . . 
end;

一种断言和显示信息之间的折衷。开发人员只需按 F9 即可继续。您可以输入一个 Abort,然后该方法将什么也不做,这将迫使他们切换方法,而 break 让他们意识到这一点。

我个人建议升级到较新版本的 Delphi。2007 和 2009 是很棒的版本,确实值得升级。

于 2009-01-13T01:11:01.377 回答
4

我最终使用的是选择进入您同意没有任何弃用代码的系统的组合,否则输出调试字符串和断点。

stricthtml 一样,我创建了一个Strict定义。

如果已定义,则所有通用单元都定义了过时的代码Strict。这样开发人员就同意他们的项目中不会有弃用的代码:

{$IFNDEF Strict}
procedure TStormPeaksQuest.BlowHaldirsHorn; overload; //obsolete
{$ENDIF}
procedure TStormPeaksQuest.BlowHaldirsHorn(UseProtection: Boolean); {$IFNDEF Strict}overload;{$ENDIF}


{$IFNDEF Strict}
procedure TStormPeaksQuest.BlowHaldirsHorn; //obsolete
begin
   OutputDebugString(PAnsiChar('TStormPeaksQuest.BlowHaldirsHorn is deprecated. Use BlowHaldirsHorn(Boolean)'));

   //Don't debugbreak without a debugger attached!
   if DebugHook > 0 then
        Windows.DebugBreak;

   ...
end;

因此,如果开发人员想要拥有正确的代码,并且在新事物被弃用时不得不执行代码更改,他们可以:

{$DEFINE Strict}

如果没有,那么总会有一个 OutputDebugString,任何有Debug View的人都可以看到(甚至是客户)。看到带有输出调试字符串的商业软件(甚至是微软的)很有趣。

最后,如果附加了一个调试器,那么他们会突然得到一个调试断点。如果有人问起,我可以借此机会取笑他们。

于 2010-01-29T14:52:33.267 回答
2

这并不能完全回答您的问题,但它可能会提供替代解决方案。你能不能用默认值更新原始函数...

procedure TStormPeaksQuest.BlowHaldirsHorn(UseProtection: Boolean = False);

...因此遗留代码的编译和行为相同,但新功能可供新开发人员使用。

于 2009-01-12T22:13:07.960 回答
0

为什么要这样做,为什么不想升级 Delphi 版本?

如果没有 deprecated 标记,您真的没有干净的选项来过滤已弃用方法的使用。所以这取决于你想在哪里做出让步:

  • 重命名会在编译时捕获错误(除非范围内有另一个同名的方法/函数)。
  • 所有其他方法仅在运行时被捕获。这有滑入生产代码的风险。

您可以做的是创建一个已弃用的日志。这不会激怒任何人,如果它进入生产代码也不是完全的灾难。但是,如果您的测试完全覆盖,您将抓住所有的罪魁祸首。您只需在(测试)运行后检查日志文件。

当然,最好的方法是使用 grep 查找所有出现的代码并进行更改。

于 2009-01-12T21:04:23.060 回答
0

如果它可以完成这项工作,我会同意一个可选参数。但我能想到的情况是可选参数不适合。例如,我已将函数移入新单元,但保留旧单元并将它们标记为已弃用。

我想您采用的任何解决方案也将取决于您团队的纪律。他们是否积极注意并努力纠正其应用程序的所有提示和警告?希望他们这样做,但我很惭愧地承认与我一起工作的团队(包括我自己)并没有掌握所有提示和警告。时不时我会在时间允许的情况下修复尽可能多的提示和警告,我们绝对应该修复警告,但实际上我们必须完成工作并且更专注于新功能和截止日期。

所以我的观点是,即使您可以将它们标记为已弃用或给出类似的提示/警告,您是否觉得您的团队无论如何都会花时间更改他们的代码?

于 2009-01-13T00:35:47.923 回答
0

这不是一个完整的解决方案,因为您无法区分他们是否使用了该方法,但如果它在 Delphi 5 中可用,但您可以使用$MESSAGE编译器指令在编译时发出警告。

于 2010-01-30T00:15:32.047 回答
0

没有说“修复我!” 像编译器中断。
也就是说,我有一位同事经常修改“通用代码”例程的签名……是的,这很烦人!

我的首选(即我们的团队还没有:/)方法如下:

  1. 所有开发人员都必须能够在他们自己的机器上轻松执行所有项目的完整构建。
  2. 谁决定更改通用代码,谁就应对后果负责。即修复所有受影响的代码。
    • 诚然,有时所说的开发人员可能并不非常适合正确实施和验证所有修复程序。
    • 但是,出于同样的原因,开发人员在他们自己的代码中强加“采用新合同”可能不清楚新合同的细节。IE
      • 为了使用保护,有什么特别需要做的吗?
      • 如何使用保护?
      • 关于它如何破坏现有代码的担忧是什么?
    • 这就是为什么一套全面的测试用例很重要的一个主要原因。
  3. 通常,您希望尽快应用所有更改的连锁反应。即,虽然更改的更精细的细节在原始开发人员的脑海中是新鲜的 - 在注意力转移到其他东西之前!
  4. 涟漪效应如此巨大(数千行)以至于您希望在很长一段时间内应用更改应该是一种罕见的情况。
    • 如果是这种情况,则实施一个集成到您的构建过程中的简单代码度量收集工具,以报告未完成实例的数量。

我认为第 2 点非常重要,尤其是因为它强调了团队内部合作和沟通的必要性。

回到我的开场白,你越早发现并修复错误越好。
让编译器报告中断!-- 这是我们拥有的“最早的机会”错误报告机制。

那是我的2铜!:D

于 2011-04-18T22:14:10.127 回答