为什么选择UnityEvent而不是原生C#事件?

Adr*_*nni 14 c# events unity-game-engine

我的意思是,UnityEvents比本机C#事件慢,它们仍然存储对接收器的强引用.因此,我发现使用UnityEvents而不是原生C#事件的唯一正当理由是它们与编辑器的集成.我忽略了什么吗?

Pro*_*mer 28

我忽略了什么吗?

不,你没有忽视任何东西.使用的唯一优势和理由UnityEvent是它允许您在编辑器中使用事件.这是拖放人或编辑插件的人.

另一个优点UnityEvent是它可以防止由于滥用委托或使用Unity对象的匿名委托而导致Unity对象无法释放的问题.虽然当它们的主脚本被破坏时它们会被释放.其原因是因为UnityEvent使用弱引用实现,因此删除/最小化此问题.这两件事仍然值得使用UnityEvent原生C#事件.

如果您没有制作编辑器插件,则应始终使用本机事件并委托UnityEvent,因为它具有快速的性能和较小的内存使用率.有关详细信息,请参阅帖子和帖子.


IAR*_*ARI 6

在软件设计方面,UnityEvents 相对于原生 C# 有一个events尚未讨论的优势:

本机事件不是C# 中的“第一类对象”。

  • 您无法引用事件
  • 您不能在事件上编写扩展方法
  • 您不能“从外部”调用事件

最后一个限制实际上是一个设计功能 - 如果您发现自己处于想要这样做的情况,则可能您的软件架构已经搞砸了。(例如,我正在开发一个具有“EventManager”的代码库,它只是一个仅托管多个事件的类,这些事件是从其他组件触发的 - 这是一个坏主意 - 但这远远超出了这篇文章。)
所以没有抱怨,这里的 c# 事件没有任何问题。

然而,我最近多次遇到其他点的问题。例如,UI 中的一个常见要求是,事件处理程序仅触发一次 - 即您希望将处理程序注册到事件,该处理程序在事件触发一次后自动删除自身。例如,假设您在模式对话框中有一个按钮,该按钮应该

  1. 播放一些动画,
  2. 关闭对话框,然后
  3. 启动一些其他序列或游戏逻辑。也许您想在对话框打开时注册单击处理程序,例如
    Button.onClick.AddListener(OnButtonClicked);
Run Code Online (Sandbox Code Playgroud)

但是,如果用户决定在 1. 动画期间再次按下按钮,您希望阻止单击处理程序再次执行。如果这是一次性的事情,您只需从处理程序中的单击事件中删除处理程序即可。

    Button.onClick.RemoveListener(OnButtonClicked);
Run Code Online (Sandbox Code Playgroud)

我们有数百个这样的案例,它们在我们的代码库中也有很大不同。足够远了,我真的希望能够这样写:

    Button.onClick.OneShot(OnButtonClicked);
Run Code Online (Sandbox Code Playgroud)

为此实现一个扩展方法 - 以及其他类似的好东西 - 是

  • 可以UnityEvent使用像or 这样的对象UnityEvent<T>,但是
  • 对于本机 C# 事件来说这是不可能的。

我们向所有 Unity 事件添加了多种扩展方法,以便将我们现有的代码库转向更具反应性的风格。话虽如此,但必须指出的是,由于多种原因,UnityEvent 并不是最佳解决方案,而这些原因远远超出了本文的主题。还是让我提一下,我们考虑像UniRx(虽然似乎被放弃了)或Rx.Unity这样的库- 如果反应式编程是您的团队共享的目标,那么这样做可能是明智的。


小智 5

UnityEvent主要与Unity UI系统一起使用,因为ugui需要序列化ui系统中的回调配置,例如按钮的OnClick回调。

序列化是unity游戏引擎中最重要的功能,使用c#内置事件系统,你无法进行序列化。

所以如果你使用unity UI系统,你必须使用UnityEvent,如果你想序列化回调函数配置,你必须使用UnityEvent。

在其他情况下,只需使用 C# 内置事件。