我如何制作可以在没有事件的情况下订阅的某些功能(就像 Unity 那样)?
How do I make certain functions that can be subscribed to without events (like Unity does)?
在 Unity 中,当您创建一个新的 MonoBehaviour
class 时,它会附带一整套您可以轻松挂接的函数 - 例如 Update()
、FixedUpdate()
和 Awake()
。我正在制作我自己的组件实体系统,我正在尝试添加一系列可以很容易地被我创建的组件挂钩的功能。我已经将我的基础 class 抽象化,并将 Update
和 Draw
作为可以继承的抽象函数。这工作正常,除了 all 我的组件必须实现所有这些功能;像 Initialize 这样的东西对某些组件有用但对其他组件没有用,我不确定如何模拟这种行为。
反射完成了吗?
您可以将方法定义为 virtual 和 override,而不是将它们定义为 abstract ] 只在必要时使用它们。
class BaseComponent : MonoBehaviour
{
public virtual void OnAwesomeEvent()
{
// do nothing or implement default behaviour
}
}
class ShinyComponent : BaseComponent
{
public override void OnAwesomeEvent()
{
Debug.Log("I've been waiting for this!");
// If you need the default implementation you can call it with
// base.OnAwesomeEvent()
}
}
class LazyComponent : BaseComponent
{
// I do nothing and no one cares
}
免责声明:
I'm making my own component-entity system and I'm trying to add a
range of functions that can easily be hooked onto by the components I
create.
我不是特别喜欢 Unity 在这方面的 "magic methods" 方法。我认为实施 interfaces
或 overriding virtual functions
通常是一种更清洁的解决方案。
我曾经使用过 Unity 的方法,用于一个 AI 插件,它应该调用用户定义的方法而不强制扩展 class(主要是因为我必须避免在修改 AI 的行为时重新编译代码)
无论如何,为了实现什么:
1) 发送消息
SendMessage使用纯反射实现:只有调用SendMessage
时才能知道目标方法名。
这看起来很方便(也许是,我仍然从未使用过,也觉得没有必要),但有几个缺点:
- 性能:反射是昂贵的(检查一些基准,它最终比直接方法调用慢数百倍)
- 类型不安全: 无法在编译时检查传递的参数类型是否正确。
2) MonoBehaviour 消息
这些方法(如Awake
、Update
、OnCollision
、...)略有不同,因为Unity 可以知道签名并编译委托。 (我不确定实现方式,但我做过类似的事情)。
此 article 中详细描述了实现类似内容的方法。
基本上你只在初始化中使用反射,但是一旦获得 MethodInfo
,你可以使用 Delegate.CreateDelegate
.
将方法编译为委托
结果:
- 你仍然使用反射,但只在初始化时使用
- 编译后,委托几乎与标准方法调用(或事件)一样快。
在 Unity 中,当您创建一个新的 MonoBehaviour
class 时,它会附带一整套您可以轻松挂接的函数 - 例如 Update()
、FixedUpdate()
和 Awake()
。我正在制作我自己的组件实体系统,我正在尝试添加一系列可以很容易地被我创建的组件挂钩的功能。我已经将我的基础 class 抽象化,并将 Update
和 Draw
作为可以继承的抽象函数。这工作正常,除了 all 我的组件必须实现所有这些功能;像 Initialize 这样的东西对某些组件有用但对其他组件没有用,我不确定如何模拟这种行为。
反射完成了吗?
您可以将方法定义为 virtual 和 override,而不是将它们定义为 abstract ] 只在必要时使用它们。
class BaseComponent : MonoBehaviour
{
public virtual void OnAwesomeEvent()
{
// do nothing or implement default behaviour
}
}
class ShinyComponent : BaseComponent
{
public override void OnAwesomeEvent()
{
Debug.Log("I've been waiting for this!");
// If you need the default implementation you can call it with
// base.OnAwesomeEvent()
}
}
class LazyComponent : BaseComponent
{
// I do nothing and no one cares
}
免责声明:
I'm making my own component-entity system and I'm trying to add a range of functions that can easily be hooked onto by the components I create.
我不是特别喜欢 Unity 在这方面的 "magic methods" 方法。我认为实施 interfaces
或 overriding virtual functions
通常是一种更清洁的解决方案。
我曾经使用过 Unity 的方法,用于一个 AI 插件,它应该调用用户定义的方法而不强制扩展 class(主要是因为我必须避免在修改 AI 的行为时重新编译代码)
无论如何,为了实现什么:
1) 发送消息
SendMessage使用纯反射实现:只有调用SendMessage
时才能知道目标方法名。
这看起来很方便(也许是,我仍然从未使用过,也觉得没有必要),但有几个缺点:
- 性能:反射是昂贵的(检查一些基准,它最终比直接方法调用慢数百倍)
- 类型不安全: 无法在编译时检查传递的参数类型是否正确。
2) MonoBehaviour 消息
这些方法(如Awake
、Update
、OnCollision
、...)略有不同,因为Unity 可以知道签名并编译委托。 (我不确定实现方式,但我做过类似的事情)。
此 article 中详细描述了实现类似内容的方法。
基本上你只在初始化中使用反射,但是一旦获得 MethodInfo
,你可以使用 Delegate.CreateDelegate
.
结果:
- 你仍然使用反射,但只在初始化时使用
- 编译后,委托几乎与标准方法调用(或事件)一样快。