Esempio n. 1
0
        /// <summary>
        /// Inspects the listenerObject for methods decorated with the [ListenTo] attribute.
        /// Then, Creates a delegate for each of those methods and binds it to the corresponding
        /// Signal instance registered with the SignalContext.
        /// Objects that autobind their listeners this way must call UnbindSignals()
        /// before they are destroyed.
        /// </summary>
        protected void BindSignals(System.Object listenerObject)
        {
            // Try to retrieve MethodInfo's for the targetObject from a cache first, cuz reflection is slow
            IEnumerable <MethodInfo> methodInfos = null;
            Type listenerObjectType = listenerObject.GetType();

            if (this.methodInfoCache.TryGetValue(listenerObjectType, out methodInfos) == false)
            {
                // If you REEAALLLLY have to, use reflection to look up the methodInfos and cache them
                methodInfos = listenerObjectType.GetMethods(BindingFlags.Public | BindingFlags.NonPublic | BindingFlags.Instance | BindingFlags.DeclaredOnly);
                this.methodInfoCache[listenerObjectType] = methodInfos;
            }

            // Loop though all the methodInfos on the targetObject...
            foreach (MethodInfo methodInfo in methodInfos)
            {
                // Identify listener methods by retrieving a SignalListenerAttribute associated with the methodInfo
                ListenTo[] listenerBindings = null;
                listenerBindings = (ListenTo[])methodInfo.GetCustomAttributes(typeof(ListenTo), false);

                // Should be only one ListenToAttribute since they are exclusive (if there is one at all)
                foreach (ListenTo listenTo in listenerBindings)
                {
                    // Debug.Log("ListenToAttribute:" + listenTo.SignalType);
                    // Get an ISignal reference from the signalContext based on the SignalType
                    ISignal signal = this.SignalContext.GetSignal(listenTo.SignalType);
                    if (signal != null)
                    {
                        var methodParameterCount = methodInfo.GetParameters().Length;
                        if (methodParameterCount != signal.ParameterCount)
                        {
                            throw new ArgumentException($"Incorrect number of parameters found when binding [ListenTo(typeof({ signal.GetType().Name })]. Expected to find {signal.ParameterCount} parameter(s) but found { methodParameterCount }.");
                        }

                        Delegate d = null;
                        try
                        {
                            // Create a callback listener for this methodInfo
                            d = Delegate.CreateDelegate(signal.GetListenerType(), listenerObject, methodInfo);
                        }
                        catch (ArgumentException)
                        {
                            var parameters     = methodInfo.GetParameters();
                            var parameterTypes = new Type [parameters.Length];
                            for (int i = 0; i < parameters.Length; i++)
                            {
                                parameterTypes[i] = parameters[i].ParameterType;
                            }

                            var typeMissmatchMessage = string.Empty;
                            var parameterIndex       = 0;
                            if (signal.TryGetParameterErrorMessage(parameterTypes, out typeMissmatchMessage, out parameterIndex))
                            {
                                throw new ArgumentException($"Incorrect parameter type while binding listener method `{ methodInfo.DeclaringType.Name }.{ methodInfo.Name }`. { typeMissmatchMessage } The { ToOrdinal(parameterIndex+1) } parameter in the listener method does not match what is defined by the Signal.");
                            }
                            else
                            {
                                throw;
                            }
                        }

                        signal.AddListener(d, listenTo.ListenerType);

                        // Add the signal listener to the internal list of delegates associated with the listenerObject
                        // ( so we can easily unbind all the signal listeners later. )
                        List <SignalListener> delegateList = null;
                        if (this.signalListenersByObject.TryGetValue(listenerObject, out delegateList) == false)
                        {
                            //Debug.Log("adding signal listener:" + methodInfo.Name + " for " + listenerObjectType);
                            delegateList = new List <SignalListener>();
                            this.signalListenersByObject[listenerObject] = delegateList;
                        }
                        delegateList.Add(new SignalListener(signal, d));
                    }
                    else
                    {
                        throw new InvalidOperationException($"Unable to Bind Singals for an instance of '{ listenerObjectType }'. The Signal '{ listenTo.SignalType }' is not registered with the SignalManager.");
                    }
                }
            }
        }