c# في الوحدة، كيف يونتي سحرية استدعاء جميع "واجهات"؟




unity3d interface (2)

الوحدة لديها "واجهة" كما يطلق عليه IPointerDownHandler ( IPointerDownHandler ).

يمكنك ببساطة تنفيذ أونبوانتيردون ...

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

والوحدة سوف "سحرية" استدعاء OnPointerDown في أي من هذا القبيل مونوبهافيور.

لم يكن لديك لتسجيلها، تعيين حدث، أو القيام بأي شيء آخر .

كل ما عليك فعله هو إضافة "إبوينتيردونهاندلر" و "عامة أونبوانتيردون الفراغ" إلى فئة، ويمكنك الحصول على تلك الرسائل في جميع الأوقات سحرية.

(إذا لم تكن الوحدة ديف - حتى يعمل إذا كنت إضافة واحدة فجأة في محرر أثناء تشغيل اللعبة!)

كيف الجحيم يفعلون ذلك؟

كيف يمكنني أن أفعل ذلك مع ملحق؟ انها أشبه فئة مجردة - كيف يفعلون ذلك؟ لذلك، أريد أن أفعل ذلك:

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

ثم يمكنني إضافة SomeNews إلى أي مونوبهافيور ، وبالتالي "إرسال الأخبار" لتلك البنود في أي وقت.

أنا على دراية كاملة مع مختلف الحلول البديلة. أريد أن أعرف كيف أنها تحقق هذا السلوك "السحر".

(راجع للشغل: أشعر أن الوحدة لا ينبغي أن تسمى هذه الواجهات ، لأنه، لا شيء في الأساس لا شيء على الإطلاق مثل واجهة - انها على العكس من ذلك، هل يمكن أن نقول أنها سحرية جعلت وسيلة لترث من أكثر من فئة مجردة واحدة، وأعتقد .)

وبصرف النظر:

فقط لوضوح إذا كنت لم تستخدم الوحدة من قبل، والطريقة التقليدية للقيام بذلك (أي، لأننا لا نملك الوصول إلى الوحدة السحرية) هو مثل هذا: مجرد إضافة ونيتييفنت إلى الخفي الخاص بك الذي سيتم إرسال الرسالة في سؤال:

public class BlahDaemon:MonoBehaviour
  {
  public UnityEvent onBlah;

    ...
    onBlah.Invoke();

قل لديك دروس آا، بب، سك التي تريد الحصول على الرسالة. إذا كنت جديدا على ونيتييفنت، في كثير من الأحيان كنت مجرد "اسحب في المحرر" من آا، بب، سك إلى الحدث في بلهاديمون. ومع ذلك يمكنك "تسجيل" في التعليمات البرمجية:

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

هذا هو "تقريبا جيدة" باستخدام السحر الداخلية الوحدة، على الرغم من أن أكثر فوضوي في التعليمات البرمجية. منذ كنت "تسجيل" إذا جاز التعبير في Awake ، كنت في الواقع بيغباكينغ على نفس السحر استخدام الوحدة.


عندما يتعلق الأمر زسوبديت، أونكوليسيونكسس وغيرها مونوبهافيورس، طريقة سجلات الوحدة ليست انعكاس كما كان يعتقد على نطاق واسع ولكن بعض عملية التجميع الداخلي.

كيف يتم استدعاء تحديث

لا، الوحدة لا تستخدم System.Reflection للعثور على طريقة سحرية في كل مرة تحتاج إلى استدعاء واحدة.

بدلا من ذلك، في المرة الأولى يتم الوصول مونوبهافيور من نوع معين يتم فحص البرنامج النصي الأساسي من خلال وقت البرمجة النصية (إما مونو أو IL2CPP) ما إذا كان لديه أي أساليب سحرية محددة ويتم تخزين هذه المعلومات مؤقتا. إذا كان مونوبهافيور يحتوي على طريقة معينة يتم إضافته إلى قائمة مناسبة، على سبيل المثال إذا كان البرنامج النصي يحتوي على طريقة تحديث تعريف يتم إضافته إلى قائمة من البرامج النصية التي تحتاج إلى تحديث كل إطار.

خلال لعبة الوحدة يكرر فقط من خلال هذه القوائم وينفذ طرق منه - بهذه البساطة. أيضا، هذا هو السبب في أنه لا يهم إذا كان أسلوب التحديث الخاص بك عام أو خاص.

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

في حالة واجهة، وأود أن نفترض أنها تفعل أكثر قليلا منذ واجهة مطلوب. آخر، يمكنك فقط إضافة طريقة مثل أي طرق مونوبهافيور أخرى.

افتراضي (التي يمكن أن تكون خاطئة)، فإنه يستخدم جيتكومبوننتس الأساسية على هذا غاموبجيكت. ثم قم بتكرار المصفوفة الناتجة واستدعاء الأسلوب الذي يجب تنفيذه لأنه من الواجهة.

هل يمكن أن تتكاثر مع نمط:

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

جيتنوس هي الطريقة التي يتحقق إذا كان يجب إرسال بعض الأخبار إلى الكائن. هل يمكن أن نفكر في ذلك مثل الفيزياء. رايكاست أن يعين القيم إلى رايكاستيت. هنا يملأ مرجع البيانات إذا كان المقصود من هذا الكائن لتلقي الأخبار لأي أسباب صحيحة.


يمكنك استخدام انعكاس للحصول على جميع أنواع في التجمع الذي ينفذ واجهة معينة ثم إنشاء تلك الأنواع واستدعاء الأساليب على تلك الحالات من خلال واجهة.

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






interface