在Unity中,Unity如何神奇地调用所有“接口”?

Unity有一个“接口”,因为他们称之为IPointerDownHandler ( doco )。

你只需实现OnPointerDown …

 public class Whoa:MonoBehaviour,IPointerDownHandler { public void OnPointerDown (PointerEventData data) { Debug.Log("whoa!"); } } 

Unity将“神奇地”在任何此类MonoBehavior中调用OnPointerDown

您无需注册,设置事件或执行任何其他操作

您所做的只是将“IPointerDownHandler”和“public void OnPointerDown”添加到类中,您可以随时神奇地获取这些消息。

(如果你不是Unity开发者 – 如果你在游戏运行时突然在编辑器中添加一个,它甚至可以工作!)

他们到底怎么做?

我怎么能用扩展名做到这一点? 它更像是一个抽象类 – 他们是如何做到的? 所以,我想这样做:

 public interface IGetNews { void SomeNews(string s); } 

然后我可以将SomeNews添加到任何MonoBehavior中 ,从而随时 “向这些项目发送新闻”。

我完全熟悉各种替代解决方案。 我想知道他们是如何实现这种“神奇”的行为。

(顺便说一句:我觉得Unity 不应该调用这些接口 ,因为它基本上没什么就像接口一样 – 它恰恰相反! 。你可以说它们神奇地想要从一个以上的抽象类inheritance,我想。)


在旁边:

为了清楚起见,如果你之前没有使用过Unity,那么传统的方法(即,因为我们无法访问Unity魔法)是这样的:只需将一个UnityEvent添加到你的守护进程中,它将发送消息题:

 public class BlahDaemon:MonoBehaviour { public UnityEvent onBlah; ... onBlah.Invoke(); 

假设您有Aaa,Bbb,Ccc等课程,希望得到这些消息。 如果您是UnityEvent的新手,通常只需将Aaa,Bbb,Ccc中的“编辑器”拖到BlahDaemon的活动中即可。 但是你可以在代码中“注册”:

 public class Aaa:MonoBehaviour { void Awake() { BlahDaemon b = Object.FindObjectOfType(); b.onBlah.AddListener(OnBlah); } public void OnBlah() { Debug.Log("almost as good as Unity's"); } } 

这与使用Unity的内部魔法一样“差不多”,尽管在代码中更加混乱。 既然你正在“注册”以便在Awake发言,那么你确实正在使用同样神奇的Unity。

对于XXXUpdate,OnCollisionXXX和其他MonoBehaviours,Unity注册的方式并不是reflection,因为它已被广泛认为是一些内部编译过程。

如何更新已被呼叫

不,Unity每次需要调用时都不会使用System.Reflection来查找魔术方法。

相反,第一次访问给定类型的MonoBehaviour时,底层脚本将通过脚本运行时(Mono或IL2CPP)进行检查,无论它是否定义了任何魔术方法,并且此信息都被缓存。 如果MonoBehaviour具有特定方法,则会将其添加到正确的列表中,例如,如果脚本定义了Update方法,则会将其添加到需要每帧更新的脚本列表中。

在游戏中,Unity只是遍历这些列表并从中执行方法 – 这很简单。 此外,这就是为什么Update方法是公共的还是私有的并不重要。

http://blogs.unity3d.com/2015/12/23/1k-update-calls/

在接口的情况下,我认为它需要更多,因为需要接口。 否则,您只需像任何其他MonoBehaviour方法一样添加方法。

我的假设(可能是错误的),它在这个GameObject上使用了一个基本的GetComponents。 然后迭代生成的数组并调用HAS TO BE实现的方法,因为它来自接口。

您可以使用以下内容重现该模式:

 NewsData data; if(GetNews(out data)) { IGetNews [] getNews = data.gameObject.GetComponents(); foreach(IGetNews ign in getNews){ ign.SomeNews(); } } 

GetNews是一种检查是否应该将某些新闻发送到对象的方法。 您可以将它想象为Physics.Raycast,它将值赋给RaycastHit。 如果该对象是出于任何正当理由接收新闻的话,它会填充数据引用。

您可以使用reflection来获取实现特定接口的程序集中的所有类型,然后实例化这些类型并通过接口调用这些实例上的方法。

 var types = this.GetType().Assembly.GetTypes() .Where(t=>t.GetInterfaces().Contains(typeof(IGetNews))); foreach (var type in types) { var instance = (IGetNews) Activator.CreateInstance(type); instance.SomeNews("news"); }