Подтвердить что ты не робот

В Unity, как Unity волшебным образом называет все "интерфейсы"?

Unity имеет "интерфейс", как он его называют IPointerDownHandler (doco).

Вы просто реализуете OnPointerDown...

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

и Unity будет "магически" вызывать OnPointerDown в любом таком MonoBehavior.

Вам не нужно регистрировать их, устанавливать событие или делать что-либо еще.

Все, что вы делаете, это добавить к классу "IPointerDownHandler" и "public void OnPointerDown", и вы можете получать эти сообщения в любое время волшебным образом.

(Если вы не Unity dev - он даже работает, если вы вдруг добавите его в Редактор во время игры!)

Как, черт возьми, они это делают?

Как я могу сделать это с расширением? Это больше похоже на абстрактный класс - как они это делают? Итак, я хочу сделать это:

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

а затем я могу добавить SomeNews в любое MonoBehavior и, таким образом, "отправлять новости" этим элементам в любое время.

Я полностью знаком с различными альтернативными решениями. Я хочу знать, как они достигают этого "волшебного" поведения.

(BTW: Я чувствую, что Unity должен не вызывать эти интерфейсы, так как он в основном вообще не похож на интерфейс - это нечто противоположное!. скажем, они волшебным образом намеревались наследовать более чем один абстрактный класс, я думаю.)


Помимо

просто для ясности, если вы раньше не использовали 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<BlahDaemon>();
    b.onBlah.AddListener(OnBlah);
    }

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

Это "почти так же хорошо", как использование внутренней магии Unity, хотя и более беспорядочно в коде. Поскольку вы "регистрируетесь", так сказать, в Awake, вы действительно соглашаетесь с тем же магическим использованием Unity.

4b9b3361

Ответ 1

Когда дело доходит до XXXUpdate, OnCollisionXXX и других MonoBehaviours, способ регистрации Unity не является отражением, поскольку это широко распространено мнение, но некоторый внутренний процесс компиляции.

ОБНОВЛЕНИЕ ОБНОВЛЕНИЯ

Нет, Unity не использует System.Reflection для поиска магического метода каждый раз, когда ему нужно его вызвать.

Вместо этого, при первом обращении к MonoBehaviour определенного типа базовый script проверяется через время выполнения скриптов (либо Mono или IL2CPP), имеет ли он какие-либо магические методы, определенные информация кэшируется. Если у MonoBehaviour есть определенный метод, это добавлен в правильный список, например, если script имеет метод обновления он добавляется в список скриптов, которые необходимо обновить каждый кадр.

Во время игры Unity просто выполняет итерации через эти списки и выполняет из нее методы - это просто. Кроме того, поэтому не имеет значения, если ваш метод обновления является общедоступным или закрытым.

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

В случае интерфейса я бы предположил, что он немного больше, так как требуется интерфейс. Кроме того, вы бы просто добавили метод, как и любые другие методы MonoBehaviour.

Мое предположение (это может быть неправильно), он использует базовые GetComponents в этом GameObject. Затем выполните итерацию результирующего массива и вызовите метод, который должен быть реализован, поскольку он находится из интерфейса.

Вы можете воспроизвести шаблон с помощью:

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

GetNews - это метод, который проверяет, нужно ли отправлять новости на объект. Вы могли бы подумать об этом, как Physics.Raycast, который присваивает значения RaycastHit. Здесь он заполняет ссылку на данные, если этот объект предназначен для получения новостей по каким-либо веским причинам.

Ответ 2

Вы можете использовать отражение для получения всех типов в сборке, которая реализует определенный интерфейс, а затем создает эти типы и вызывает методы в этих экземплярах через интерфейс.

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