【问题标题】:Can NIL be used for a Sender object?NIL 可以用于 Sender 对象吗?
【发布时间】:2012-03-05 16:42:20
【问题描述】:

最近我被要求自动化一个小子程序,该程序显示一系列数据记录和四个潜在按钮中的任意两个,供用户在查看记录分析后选择。老板说让用户看到分析是在浪费时间,因为用户总是选择按钮列表中的第一选择,他准备接受我对除了最好的用户之外的所有用户的猜测。因此,他希望添加一系列新按钮,以提供自动处理、手动处理和逐个处理。最后一个按钮只会运行已经存在的代码。第二个按钮基本上什么都不做,只是退出。第一个按钮?嗯,这就是问题所在。

我决定做的是使用几个标志,然后根据分析让自动路径只模拟最佳子按钮的点击。问题是调用 Button1Click(Sender) 是不可能的,因为运行分析的过程称为 RunAnalysis 并且没有附加到特定对象以传递 TObject。我最终将 Button1Click 方法的内容重构为 Button1Pressed,然后从 Button1Click 调用 THAT。因此,我能够从 RunAnalysis 中调用 Button1Pressed。

避免的路径是调用 Button1Click(Nil)。我没有尝试过,因为我有一个简单的解决方案(顺便感谢 Modelmaker)。但我的问题是,零参考会起作用还是会造成灾难。我可以调用一个更高的函数(随机?),它确实有一个发送者,只是为了在过程调用中有一个发送者对象?如果我不使用任何实际引用发件人的东西,发件人对象到底有多重要?

系统详情:Delphi 7 在 Win 7 编程环境中用于 Windows XP。

提前感谢您的智慧,GM

【问题讨论】:

  • 您可以使用nilSender 参数调用事件处理程序,前提是事件处理程序确实尝试访问Sender 对象。但是,您应该知道,无论如何最好不要直接调用事件处理程序。如果你想假装按下按钮,你只需调用按钮的Click 方法。
  • 大卫,我无法调用 click 方法,因为没有 Sender 可以通过。即 Button1Click(sender);出错了。我曾想过在 RunAnalysis 过程中执行 Button1Click(nil),但担心会发生灾难,最后将原始 Button1Click 更改为在没有任何参数的情况下调用 Button1Pressed。然后,我可以将 RunAnalysis 中的调用更改为 Button1Pressed。在任何一个 Button1 活动处理程序中,我都没有引用 Sender。因此我的问题。感谢您的评论和肯定 Nil 在这种情况下是一个合法的参考。
  • 不,我的意思是你有Button: TButton,然后写Button.Click。您应该始终更喜欢直接调用事件处理程序。它们真的应该只被框架调用。
  • 每当我不需要给发件人的时候,我都会通过nil。在你的情况下,它应该是安全的,只要你不假设它会被分配到另一端的某个地方。不过,在某些情况下,您确实需要小心传递 nil

标签: delphi delphi-7


【解决方案1】:

如果可能,我倾向于将事件处理程序的代码放入另一个方法中:

procedure TForm1.DoSomething(const Test: Boolean);
begin
  // Do Something based on Test
end;

procedure TForm1.FormCreate(Sender: TObject);
begin
  DoSomething(False); // init here
end;

procedure TForm1.CheckBox1Click(Sender: TObject);
begin
  DoSomething(TCheckBox(Sender).Checked);
end;

因此,当我需要调用 CheckBox1Click(nil) 时,将代码从事件处理程序中提取到单独的方法中是一个好兆头。

【讨论】:

  • 科比克,最终,这就是我所做的。我将 Button1Click(sender) 方法基本上简化为 Button1Pressed,并将所有代码从 click 方法移到了 press 方法。这允许我从没有 Sender 对象的过程中调用 Button1Pressed。我实际上并没有尝试 nil 参数,因为担心会搞砸昨天需要的编程请求。但它确实看起来 nil 会起作用,但正如你所说,编程实践很差。感谢您的评论。
  • 顺便说一句,您应该设置一个有意义的名称,而不仅仅是 Button1Pressed 来描述该方法。
【解决方案2】:

简短回答 - 是的。

我用它来区分(比如说)一个菜单事件是被用户点击还是被代码直接调用。

【讨论】:

  • 调度员,感谢您的简洁。我喜欢你如何特别使用 NIL 来区分。但是其他 cmets 让我认为重构而不使用 nil 参数可能是处理这些情况的正确方法。感谢您的评论。
  • 我在上面看到您对 Ken 的评论,他是正确的。他和我(尽管简短地)回答了这个问题——安全吗?如果被调用的事件没有对 Sender 进行假设,并且对 sender 的内容进行假设是不安全的,那么它是安全的。
【解决方案3】:

只要代码不引用Sender,您就可以将nil 用作TNotify 事件(或任何其他期望Sender)的参数:

procedure TForm1.Button1Click(Sender: TObject);
begin
  DoSomeStuff(nil);
end;

procedure TForm1.DoSomeStuff(Sender: TObject);
begin
  // Safe
  DoSomeOtherStuff;
  // Safe

  // Do stuff with Sender
  if Sender is TButton then
    TButton(Sender).Caption := 'In DoSomeStuff'

  // NOT safe!
  with TButton(Sender) do
  begin
    Caption := 'In DoSomeStuff';
  end;
end;

【讨论】:

  • Ken,我没有以任何方式使用 Sender,仅当我想从没有参数的过程中运行 Button1Click 过程时才涉及它。问题归结为 NIL 在调用 DID 需要 Sender 对象的过程(即 Button1Click(Sender))时是否可以安全替换,但是我没有在任何代码中使用 Sender 的过程。感谢您的评论。
  • 我直接回答了这个问题。请参阅DoSomeStuff 中的第一行,紧随begin;它说明了只要您不引用Sender,就可以安全地使用nil 调用。另外两个是两种方式的演示(有和没有nilSender)。这不是“评论”;这是对所提问题的完整回答。 :)
【解决方案4】:

回调或“事件”与任何其他函数没有什么不同。你可以在任何你想要的地方传递一个 NIL 引用,只要你 (a) 编写了该代码并且知道它是 nil 安全的,或者 (b) 你已经阅读了该代码及其调用的所有内容而不检查 nil,并且知道它是 nil 安全的.

有些程序员随意使用 NIL,有些人认为使用 NIL 参数值是不好的风格。我的风格倾向于“不要假设 Sender 已分配并且不要假设它是特定类型”,这导致我的事件处理程序中有很多检查代码,但我的其他代码,它变化很大并且所以第一条编码规则就出现了; “不要做假设。阅读代码。”。

【讨论】:

  • Warren,对 Kobik 的回应是,我可以做到这一点令人欣慰,但选择了一个更好的编程解决方案,只需很少的额外工作。感谢您的评论。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2019-06-10
  • 2011-04-30
  • 1970-01-01
  • 2011-09-04
  • 1970-01-01
相关资源
最近更新 更多