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

时间:2016-03-27 18:34:52

标签: c# unity3d interface

Unity有一个"界面":

IPointerDownHandlerdoco

您只需实施OnPointerDown ...

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

和Unity将会神奇地"在任何此类MonoBehavior中调用OnPointerDown

您不必注册,设置活动,也不需要做任何其他事情

你在语法上做的就是添加" IPointerDownHandler"和#34; public void OnPointerDown"到了一个班级,你可以神奇地获得这些信息。

(如果您不是Unity开发者 - 如果您在游戏运行时突然在编辑器中添加一个,它甚至会起作用!)

他们到底怎么做,我该怎么做?

所以,我想这样做:

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

然后我可以将SomeNews 添加到任何MonoBehavior

替代解决方案显而易见,我想具体了解Unity如何实现这一点" magic"行为。

(顺便说一句:我觉得他们不应该把这些称为"接口",因为它基本上没有任何东西像接口一样 - 它恰恰相反!你可以说他们神奇地想要从一个以上的抽象类继承,我想。)

除了:

如果您之前没有使用过Unity,那么传统的方法就是这样做 - 因为我们无法访问Unity魔法 - 只需向您的守护程序添加一个UnityEvent,它将发送有问题的消息:

public class BlahDaemon:MonoBehaviour
  {
  public UnityEvent onBlah;

    ...
    onBlah.Invoke();

假设您有Aaa,Bbb,Ccc等课程,希望得到这些消息。只需连接Unity事件(通过在编辑器或代码中拖动),例如:

public class Aaa:MonoBehaviour
  {
  void Awake()
    {
    BlahDaemon b = Object.FindObjectOfType<BlahDaemon>();
    b.onBlah.AddListener(OnBlah);
    }

  public void OnBlah()
    {
    Debug.Log("almost as good as Unity's");
    }
  }

你基本上&#34;注册&#34;你在Awake的召唤,你确实在捎带神奇的Unity使用 - 无论它是什么。但我想直接使用魔法。

2 个答案:

答案 0 :(得分:26)

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

  

如何更新

     

不,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<IGetNews>();
    foreach(IGetNews ign in getNews){ ign.SomeNews(); }
}

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

答案 1 :(得分:3)

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

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");
}