【问题标题】:How to initialize Boolean type to be used by local variables?如何初始化局部变量使用的布尔类型?
【发布时间】:2016-11-25 17:10:05
【问题描述】:

我正在尝试更改如何使用布尔参数来获得有意义的名称,因此我不需要检查每个方法 True/False 的含义。在此示例中,我使用 True/False:

procedure ProcessData(Param1, Param2: string; CreateOnEmpty: boolean = False);

procedure TForm1.Button1Click(Sender: TObject);
begin
  ProcessData(P1, P2, True);  // when CreateOnEmpty should be True
  ProcessData(P1, P2);        // when CreateOnEmpty should be False
  ProcessData(P1, P2, False); // when CreateOnEmpty should be False
end;

但在这种情况下,我需要查找 ProcessData 方法以了解 True/False 参数的含义,这样做。

所以,我从这个示例开始,为参数分配有意义的名称:

procedure TForm1.Button2Click(Sender: TObject);
var
  vCreateWhenEmpty: boolean;
  vDontCreateWhenEmpty: boolean;
begin
  // Init control params
  vCreateWhenEmpty := True;
  vDontCreateWhenEmpty := False;

  ProcessData(P1, P2, vCreateWhenEmpty);     // When CreateOnEmpty should be True
  ProcessData(P1, P2, vDontCreateWhenEmpty); // When CreateOnEmpty should be False
end;

但是,我想避免初始化局部变量并且正在考虑这样的事情:

procedure TForm1.Button3Click(Sender: TObject);

Type
  TBoolTrue = Boolean = True;    // Init to True and all local vars will be True
  TBoolFalse = Boolean = False;  // Init to False and all local vars will be False

var
  vCreateWhenEmpty: TBoolTrue;      // Variable should default to True
  vDontCreateWhenEmpty: TBoolFalse; // Variable should default to False
begin
  ProcessData(P1, P2, vCreateWhenEmpty);     // When CreateOnEmpty should be True
  ProcessData(P1, P2, vDontCreateWhenEmpty); // When CreateOnEmpty should be False
end;

所以,我可以跳过分配值 True/False。

我有 100 多个接受布尔参数的方法,因此可以用作参数的 100 多个常量或全局变量听起来有点过头了。

是否有可能以某种方式将布尔类型初始化为 True/False 或使用其他技巧避免初始化局部变量?

编辑:

我在示例中将布尔类型设置为局部类型,我的意思是将它们设置为全局类型,因此它们只在每个方法中设置一次,而不是每次都设置。 所以,这将是全球性的,而不是本地的:

Type
      TBoolTrue = Boolean = True;    // Init to True and all local vars will be True
      TBoolFalse = Boolean = False;  // Init to False and all local vars will be False

编辑 2:

我希望问题不会结束,因为答案中有一些很好的建议。所以我的选择是:

  • 全局常量(我最终会得到 100 个新常量)

  • 全局枚举字段(即使我最终会得到 100 个,与 const 一样,如果我添加第三个值,它们可以更轻松地扩展值)

  • 本地常量(我喜欢这个很短,每个常量 1 行,它是本地的,而不是全局的)
  • 局部变量(每个变量 2 行,定义和初始值 - 太多)
  • 本地枚举字段(我喜欢这个,因为它可以使用第三个或第四个值进行扩展...)
  • Sir Rufo 的自动初始化记录示例(虽然有点过头,但正是我想要的;不幸的是,这是一个真正过头的实现;性能可能会受到影响,但有可用的解决方案 - 很好)李>
  • 保持原样并依靠代码洞察力快速了解参数 - 不幸的是,在 XE7 中不稳定且无法依赖;也许在较新的版本中会更好,但从对较新版本的反馈来看,我怀疑它是否会按预期工作。

决定

尽管 Rufo 爵士关于如何做我所想的事情的技巧是独一无二的,但我意识到我正在尝试实现当前 Delphi 版本所不具备的东西。因此,我将使用 const 和枚举类型的组合,并且只在真正需要的地方应用,而不是在任何地方应用,并且将避免使用 100 多个全局、局部变量。

【问题讨论】:

  • 坏主意。显式代码将更易于维护。
  • 你在问是否可以初始化一些东西,这样你就可以避免初始化它。嗯?
  • @RobKennedy 是:初始化全局值一次,并用局部变量引用这个值。
  • 为什么不制作像 const vCreateWhenEmpty 这样的本地类型常量:Boolean = True。它将位于数据段中,而不是堆栈中,并且您仍然可以仅在本地访问它,而不会像下面的回答那样浪费全局空间。
  • @ZENsan:全局范围的建议是基于它们将在多个地方使用的理解。如果没有,局部常量可以正常工作。

标签: delphi boolean delphi-xe7


【解决方案1】:

无法自动初始化局部变量。您必须在代码中这样做,或者(尽管不想)使用 const 而不是类型,声明在与将使用它们的函数相同的范围内。

const
  vCreateWhenEmpty = True;
  vDontCreateWnenEmpty = False;

procedure ProcessData(Param1, Param2: string; CreateOnEmpty: boolean = False);

稍后:

  ProcessData(P1, P2, vCreateWhenEmpty); 
  ProcessData(P1, P2, vDontCreateWhenEmpty);

我个人会将布尔变量替换为带有公共前缀的枚举类型。

type
  TProcessDataCreateOpt = (coCreate, coSkip);

  procedure ProcessData(Param1, Param2: string; CreateOpt: TProcessDataCreateOpt = coSkip);

这使它更具可读性,Code Insight 和 Code Completion 可以帮助您获得正确的值,并且您根本不需要任何局部或全局变量。

【讨论】:

  • 希望避免为所有接收布尔值的方法创建 100 个 const。因为 Create(Dont)WhenEmpty 仅适用于 1 个方法(或者可能是 2 个)的名称。需要创建 100 个具有不同名称的 const 来解释不同方法的参数。
  • OP 说他想避免在他的问题中使用 const
  • 枚举类型在这种情况下是完美的 +1
  • @RemyLebeau:OP 通过尝试创建这两种类型然后创建这两种类型的预初始化的两个局部变量来有效地做更多的工作。那是四行代码(两个类型声明加上两个 var 声明),而不是枚举的单个类型声明。问题本身就是一个 XY 问题;带有枚举的正确设计意味着不存在正在解决的问题。
  • 如果我使用枚举,那么我可以用If CreateOpt = coCreate then... 检查CreateOpt 参数值,这也很好。好的。
【解决方案2】:

我认为您应该按照自己的方式保留它。如果您想查看参数的名称是什么,您可以简单地使用代码洞察力来做到这一点。

如果您还没有使用这些,那么您应该开始并让您的生活更轻松:

  • Ctrl + Shift + Spacebar 调用代码参数提示 Delphi 5 及更高版本
  • Ctrl + Shift + UpArrow 导航到方法实现/声明 Delphi 5 及更高版本
  • Ctrl + 单击转到声明。

【讨论】:

  • 在尝试使用代码洞察力时,很多时候它不起作用或需要很长时间才能完成“解析...”。
【解决方案3】:

没有办法自动初始化局部变量。

但是我们可以创建一个行为类似于自动初始化的局部变量的记录。

type
  TBoolDefaultTrue = record
  private const
    InitializedFlag = '*';
    DefaultValue = True;
  private
    FIsInitialized: string;
    FValue: Boolean;
    procedure EnsureInitialized;
  public
    class operator implicit ( const v: Boolean ): TBoolDefaultTrue;
    class operator implicit ( const v: TBoolDefaultTrue ): Boolean;
  end;

procedure EnsureInitialized;
begin
  if FIsInitialized = ''
  then 
    begin
      FValue := DefaultValue;
      FIsInitialized := InitializedFlag;
    end;
end;

class operator TBoolDefaultTrue.Implicit( const v: Boolean ): TBoolDefaultTrue;
begin
  Result.FValue := v;
  Result.FIsInitialized := InitializedFlag;
end;

class operator TBoolDefaultTrue.Implicit( const v: TBoolDefaultTrue ): Boolean;
begin
  v.EnsureInitialized;
  Result := v.FValue;
end;

您可以在不更改方法签名的情况下使用它

procedure TForm1.Button3Click(Sender: TObject);
var
  vCreateWhenEmpty: TBoolDefaultTrue;
  vDontCreateWhenEmpty: TBoolDefaultFalse;
begin
  ProcessData(P1, P2, vCreateWhenEmpty);     // When CreateOnEmpty should be True
  ProcessData(P1, P2, vDontCreateWhenEmpty); // When CreateOnEmpty should be False
end;

这只是您可以选择的一个选项,但对我来说,这不是我想要的。我喜欢肯在他的回答中描述的枚举方式。我只会选择不同的名字。

TProcessDataOption = ( pdoDontCreateWhenEmpty, pdoCreateWhenEmpty );

但那只是糖

【讨论】:

  • 这确实有效,我喜欢它,但正如你所说,这似乎有点矫枉过正。我认为这也不适用于需要性能的地方。
  • 我也希望枚举更好的名称,但我认为 OP 可以按照他们认为适合自己的代码的方式命名它们。这个解决方案绝对是独一无二的(而且相当巧妙),但我不认为它是我将在不久的将来随时使用的任何东西。 :-) 赞成创造性的解决方案,不过。 :-)
【解决方案4】:

正如其他人所说,目前没有办法初始化局部变量,但真正的问题是为什么它应该是变量。我从您的代码中了解到,在代码中初始化这些变量后,它们将永远不会改变它们的值。该方法也没有将这些参数声明为变量。在这种情况下,也可以通过局部常量来完成(只是为了避免全局常量)。因此,与其声明局部变量并在代码中初始化它们,不如声明局部常量。

procedure TForm1.Button3Click(Sender: TObject);
const
  cCreateWhenEmpty = True;
  cDontCreateWhenEmpty = False;
begin
  ProcessData(P1, P2, cCreateWhenEmpty);     // When CreateOnEmpty should be True
  ProcessData(P1, P2, cDontCreateWhenEmpty); // When CreateOnEmpty should be False
end;

从长远来看,我还建议将声明的枚举类型用作参数,但如果您无法更改声明,上述解决方案应该可以很好地满足您的问题中提到的要求。

【讨论】:

    【解决方案5】:

    除了其他人已经建议的之外,如果您可以更改 ProcessData 方法的实现,您可以使用枚举而不是布尔值:

    type
      TCreateDisposition = (cdDontCreate, cdCreateIfEmpty);
    
    procedure ProcessData(Param1, Param2: string; CreateDisposition: TCreateDisposition);
    

    【讨论】:

    • 我在回答中提到了枚举。
    • @KenWhite 抱歉,我错过了。
    • 如果您无权访问原始源,您也可以随时“更改”签名 ˋprocedure Bar( arg: string );开始 FooUnit.Bar( arg = '*' );结束;ˋ ;o)
    猜你喜欢
    • 1970-01-01
    • 2023-01-27
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2021-03-17
    相关资源
    最近更新 更多