Search Unity

[Reflection] Method selection with an editor script

Discussion in 'Scripting' started by Sock Puppet, Jul 4, 2012.

  1. Sock Puppet

    Sock Puppet

    Joined:
    Jan 9, 2011
    Posts:
    77
    I want to be able to select a method from a class using an editor script, save/serialize that selection, then call that method when the game is playing. I've got as far as using reflection to get a list of the methods I want but I'm unsure on how best to save the selection and invoke the method at runtime.

    I tried using Delegate.CreateDelegate() to bind the selection but to no avail so far.

    Code (csharp):
    1.  
    2. using UnityEngine;
    3. using UnityEditor;
    4. using System.Collections.Generic;
    5. using System.Reflection;
    6.  
    7.  
    8. [CustomEditor(typeof(FunctionTest))]
    9. public class InspectorFunctionTest :  Editor
    10. {
    11.     FunctionTest owner;
    12.    
    13.     List<MethodInfo> methods;
    14.    
    15.  
    16.     void OnEnable()
    17.     {
    18.         owner = (FunctionTest)target;
    19.            
    20.         // get methods 
    21.         MethodInfo[] allMethods;
    22.         allMethods = owner.GetType().GetMethods(BindingFlags.Instance | BindingFlags.NonPublic);
    23.        
    24.        
    25.         //...do some filtering and save results to method List
    26.     }  
    27.    
    28.    
    29.     public override void OnInspectorGUI()
    30.     {      
    31.         //...use GUI functions to select the right MethodInfo from List
    32.                
    33.        
    34.         if(GUI.changed)
    35.         {
    36.             // save selection to the owner in a way that can be called at runtime
    37.            
    38.             EditorUtility.SetDirty(owner);
    39.         }
    40.     }
    41. }
    42.  
    Thanks.
     
  2. eduardo-pons

    eduardo-pons

    Joined:
    Mar 31, 2009
    Posts:
    176
    This method receives an object and invoke its method called "p_method" with 0 or more argments.

    Code (csharp):
    1.  
    2.  
    3.         static private BindingFlags _flags = BindingFlags.Instance | BindingFlags.NonPublic | BindingFlags.Public | BindingFlags.Static;
    4.  
    5.         static public object Invoke(object p_target, string p_method, params object[] p_args)
    6.         {
    7.             Type t = p_target.GetType();
    8.             MethodInfo mi = t.GetMethod(p_method, _flags);
    9.             if (mi == null) return null;
    10.             return mi.Invoke(p_target, p_args);
    11.         }
    12.  
    13. //Example
    14. Invoke(gameObject,"SetActiveRecursively",true)
    15.  
    16.  
     
    samana1407 likes this.
  3. fholm

    fholm

    Joined:
    Aug 20, 2011
    Posts:
    2,052
    I was bored, here's a complete example of a behaviour (FunctionDemo) and it's associated editor (FunctionDemoEditor):

    FunctionDemo.cs
    Code (csharp):
    1. using UnityEngine;
    2. using System.Collections;
    3. using System.Reflection;
    4.  
    5. public class FunctionDemo : MonoBehaviour
    6. {
    7.     public string MethodToCall;
    8.  
    9.     void Start()
    10.     {
    11.         typeof(FunctionDemo)
    12.             .GetMethod(MethodToCall, BindingFlags.Instance |BindingFlags.NonPublic | BindingFlags.Public)
    13.             .Invoke(this, new object[0]);
    14.     }
    15.  
    16.     void Update()
    17.     {
    18.  
    19.     }
    20.  
    21.     void Foo()
    22.     {
    23.         Debug.Log("Foo");
    24.     }
    25.  
    26.     void Bar()
    27.     {
    28.         Debug.Log("Bar");
    29.     }
    30. }
    31.  
    FunctionDemoEditor.cs
    Code (csharp):
    1.  
    2.  
    3. using UnityEngine;
    4. using UnityEditor;
    5. using System.Linq;
    6. using System.Collections;
    7. using System.Reflection;
    8. using System;
    9.  
    10. [CustomEditor(typeof(FunctionDemo))]
    11. public class FunctionDemoEditor : Editor
    12. {
    13.     static string[] methods;
    14.     static string[] ignoreMethods = new string[] { "Start", "Update" };
    15.  
    16.     static FunctionDemoEditor()
    17.     {
    18.         methods =
    19.             typeof(FunctionDemo)
    20.             .GetMethods(BindingFlags.Instance | BindingFlags.NonPublic | BindingFlags.Public) // Instance methods, both public and private/protected
    21.             .Where(x => x.DeclaringType == typeof(FunctionDemo)) // Only list methods defined in our own class
    22.             .Where(x => x.GetParameters().Length == 0) // Make sure we only get methods with zero argumenrts
    23.             .Where(x => !ignoreMethods.Any(n => n == x.Name)) // Don't list methods in the ignoreMethods array (so we can exclude Unity specific methods, etc.)
    24.             .Select(x => x.Name)
    25.             .ToArray();
    26.     }
    27.  
    28.     public override void OnInspectorGUI()
    29.     {
    30.         FunctionDemo obj = target as FunctionDemo;
    31.  
    32.         if (obj != null)
    33.         {
    34.             int index;
    35.  
    36.             try
    37.             {
    38.                 index = methods
    39.                     .Select((v, i) => new { Name = v, Index = i })
    40.                     .First(x => x.Name == obj.MethodToCall)
    41.                     .Index;
    42.             }
    43.             catch
    44.             {
    45.                 index = 0;
    46.             }
    47.  
    48.             obj.MethodToCall = methods[EditorGUILayout.Popup(index, methods)];
    49.         }
    50.     }
    51. }
    52.  
     
    Last edited: Jul 4, 2012
    GamitusLabs, Eldoir, wxxhrt and 3 others like this.
  4. Sock Puppet

    Sock Puppet

    Joined:
    Jan 9, 2011
    Posts:
    77
    Awesome, thanks a lot guys.
     
  5. badr_douah

    badr_douah

    Joined:
    Jun 22, 2017
    Posts:
    22
    @fholm i'm trying to get the name of all methodes of all monoscripts on a defined gameObject ,the problem is that i'm getting all monobahaviours methods as well even with the flag set ,i tried the
    Code (CSharp):
    1. .Where(x => x.DeclaringType == typeof(FunctionDemo)) // Only list methods defined in our own class
    but it doesn't seam to work , do you have any solution to this thanx


    Code (CSharp):
    1.  
    2.         GameObject Obj = this.gameObject;
    3.  
    4.  
    5.         MonoBehaviour[] allBehav = Obj.GetComponents<MonoBehaviour>() as MonoBehaviour[];
    6.  
    7.         foreach (var Behav in allBehav)
    8.         {
    9.             //  Debug.Log( Behav.GetType().ToString());
    10.             MethodInfo[] classMethods = Behav.GetType().GetMethods(BindingFlags.Instance | BindingFlags.Public |  BindingFlags.NonPublic);
    11.             foreach (var Method in classMethods)
    12.             {
    13.                 Debug.Log("Methode name" + Method.Name);
    14.             }
    15.  
    16.         }
    17.  
     
  6. badr_douah

    badr_douah

    Joined:
    Jun 22, 2017
    Posts:
    22
    Issue fixed

    Code (CSharp):
    1.        
    2.  
    3.    using System.linq
    4. GameObject Obj = this.gameObject;
    5.  
    6.         MonoBehaviour[] allBehav = Obj.GetComponents<MonoBehaviour>() as MonoBehaviour[];
    7.  
    8.         foreach (var Behav in allBehav)
    9.         {
    10.             //  Debug.Log( Behav.GetType().ToString());
    11.             Type currentType = Behav.GetType();
    12.              IEnumerable <MethodInfo>  classMethods = currentType.GetMethods(BindingFlags.Instance | BindingFlags.NonPublic)
    13.                 .Where(x => x.DeclaringType ==  currentType  );
    14.  
    15.             foreach (var Method in classMethods)
    16.             {
    17.                 Debug.Log("Methode name" + Method.Name);
    18.             }
    19.  
    20.         }