private void AssignDelegate(object model, ISignal signal, MethodInfo method) { try { if (signal.GetType().BaseType.IsGenericType) { Type genericActionType = typeof(Action<>).MakeGenericType(signal.GetType().BaseType.GetGenericArguments()); signal.AddListener(Delegate.CreateDelegate(genericActionType, model, method)); } else { signal.AddListener((Action)Delegate.CreateDelegate(typeof(Action), model, method)); } } catch (Exception e) { Debug.LogError(e.GetType() + " " + e.Message + " " + signal.GetType().Name + " " + method.Name); } }
/// <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."); } } } }