【问题标题】:How to use argument in a cast with Delphi如何在 Delphi 的演员阵容中使用参数
【发布时间】:2009-11-12 12:32:10
【问题描述】:

如何在 Delphi 中做到这一点:

procedure ToggleVisibility(ControlClass : TControlClass);
var
  i : integer;
begin
  for i := 0 to ComponentCount - 1 do
    if Components[i] is ControlClass then
      ControlClass(Components[i]).Visible := not Control(Components[i]).Visible;
end;

编译器在这种情况下不允许强制转换。有什么想法吗?

我使用的是 Delphi 2007。

【问题讨论】:

  • stackoverflow.com/questions/1083087/… 的可能重复项 - 我不确定,因为我不能 100% 确定我理解您要做什么。
  • 为什么调用参数ComponentClass,却是TControlClass类型?参数不应该改为ControlClass吗?
  • @Harriv:这样的编辑有点不幸,因为以后很难说为什么答案使用了不同的(更糟糕的)命名方案。我完全同意 Jeroen 的观点(如果你也这样做,你也应该支持他的评论),但是这个编辑可能应该被回滚。您还引入了另一个错误。

标签: delphi casting


【解决方案1】:

由于组件是 TControl 或后代,因此您必须强制转换为 TControl

procedure ToggleVisibility(ComponentClass : TControlClass);
var
  i : integer;
begin
  for i := 0 to ComponentCount - 1 do begin
    if Components[i] is ComponentClass then
      TControl(Components[i]).Visible := not TControl(Components[i]).Visible;
  end;
end;

【讨论】:

  • 如果您稍后将 TControlClass 更改为其他内容会怎样。很容易忘记你认为理所当然的依赖。
  • @Tihauan:是的。我没有考虑太多,因为我认为整个想法有缺陷,并且永远不会编写这样的程序。请注意,它甚至无法按原样编译,与问题中的代码相同。
  • 你不是说“如果 Components[i] 是 TControl”吗?
  • @David:请参阅我对您的回答的评论。它在controls.pas
  • @David Components[i] is ComponentClass 检查 Componets[i] 是否属于该方法应处理的类。 TControl(Components[i]) 是访问 Visible 属性的方式。没错,因为与 TControlClass 兼容的类的每个实例都是 TControl 的后代。为了使代码更好地阅读 var ComponentClass 应重命名为 ControlClass
【解决方案2】:
(Components[i] as ComponentClass).Visible

【讨论】:

  • 如果我正确理解了这个问题,这将不起作用,因为 ComponentClass 是一个元类,您不能使用其中一个进行转换。我回复了更多解释 - 只是想我应该解释一下否决票。
  • 感谢您的解释。实际上可以使用类类型进行安全转换。不信可以试试代码。
  • 我现在没有 Delphi,但我会相信你的话!我只是试图撤消反对票,但它说它太旧了 - 对不起:/
  • 嗯,然后由我们来投票。虽然.. 我手头有 Delphi,而 'TComponent' 没有 Visible 属性,所以我担心我的赞成票会转到 mghie 的帖子。
  • @Tihauan:您当然是正确的,我也不理解反对票。 +1 弥补他们。
【解决方案3】:

强制转换 ComponentClass(Components[i]).Visible 没有意义,因为 .Visible 需要属于特定类才能正确编译。因此,您需要指定应该转换到的确切类。例如,如果 TControl 具有 .Visible 属性,但派生类创建了一种新的 .Visible 属性,编译器将不知道它应该为这两个属性中的哪一个进行编译。

所以问题是,你想反转 TControl.Visible,那么你应该写 (Components[i] as TControl).Visible。我想这就是你想要的。

如果你想反转任何 TControl 后代的 .Visible ,无论它是否与控件 Visible 相关,也不管它是否与 TControl.Visible 相关,那么你应该选择 RTTI其他地方描述的解决方案。

【讨论】:

    【解决方案4】:

    使用 RTTI 尝试此选项

    Uses
     TypInfo;
    
    procedure TForm1.ToggleVisibility(ComponentClass: TClass);
    var
      i       : integer;
      PropInfo: PPropInfo;
      aValue  : Variant;
    begin
      for i := 0 to ComponentCount - 1 do
        if Components[i] is ComponentClass then
         begin
          PropInfo := GetPropInfo(Components[i].ClassInfo, 'Visible');
          if Assigned(PropInfo) then
          begin
           aValue:=GetPropValue(Components[i], 'Visible');
           if PropInfo.PropType^.Kind=tkEnumeration then //All enumerated types. This includes Boolean, ByteBool, WordBool, LongBool and Bool
           SetOrdProp(Components[i], PropInfo, Longint(not Boolean(aValue)));
          end;
         end;
    end;
    

    执行

    ToggleVisibility(TEdit);
    

    【讨论】:

    • 您确定所有可能的 Delphi 组件上的所有属性 Visible 都是可以硬转换为 Boolean 的类型吗?
    • @mghie 要更改属性的类型,您需要重新声明该属性。但是通过属性 Visible 的重新声明,您可以隐藏/显示控件,这样您的代码也可能不会像预期的那样工作。 :-)
    • @Heinz:这可能是真的,但对于上面的代码并不重要。请注意,该方法接受任何类的参数,因此传递的实例不必是控件,因此可能具有完全不同的Visible 属性。由于没有类型约束,因此不应在代码中对其进行任何假设。
    • @mghie:我错过了 RRUZ 使该方法比原始海报所需的更通用。
    • 有趣的解决方案,但复杂。有没有理由使用这种解决方案?
    猜你喜欢
    • 2013-10-02
    • 1970-01-01
    • 2021-06-13
    • 2014-04-05
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2013-05-01
    相关资源
    最近更新 更多