- Home /
Question was refined and moved to new thread
using System.Reflection in Custom Editor for flexible tool (somewhat long)
I'm attempting to create a custom editor that allows for multiple behaviors to be attached to an object in the editor.
The goal of the tool: I'd like to be able to create subclasses that derive from a base class that can be assigned into a custom script I've written.
The goal of the inspector: I'd like to be able to automatically detect available subclasses and offer them as selections to be added, without having to write new code each time a new subclass is written.
The code I've got so far: please note, this is my first foray both into System.Reflection and also Custom Editors, so please point out if I'm just barking up the wrong tree entirely, or flat out doing things wrong. Thanks in advance!
Editor Class:
using UnityEngine;
using UnityEditor;
using System.Collections;
[CustomEditor (typeof(Container))]
public class ContainerEditor: Editor
{
private SerializedObject obj;
public void OnEnable()
{
obj = new SerializedObject(target);
}
public override void OnInspectorGUI()
{
foreach (var item in SubclassFinder.FindDerivedTypes<ReturnBehavior>(null)) //this works if I only return the names of classes. if I can somehow return a reference or create a way to instantiate a class from here, that would be ideal
GUILayout.Label(item.ToString(), EditorStyles.miniBoldLabel);
}
}
container class:
public class Container : MonoBehaviour
{
public FunBehaviors[] funBehaviors;
void Start ()
{
}
void Update ()
{
}
}
base FunBehavior class:
public class FunBehavior
{
public Container container;
public FunBehavior ()
{
//CONTAINER OF FUN
}
}
child class #1
public class SooperOssmFun: FunBehavior
{
public SooperOssmFun(Container c)
{
//OMG ALL TEH FUNTIEMZ
container = c;
}
}
child class #2
public class MegaOssmFun: FunBehavior
{
public MegaOssmFun(Container c)
{
//NO SRSLY LIEK WOAH FUNTIEMZ
container = c;
}
}
static class to return classes to be displayed in inspector and later added to the container script on Editor controls.
using System;
using System.Reflection;
using System.Collections;
using System.Collections.Generic;
using System.Linq;
public static class SubclassFinder
{
public static IEnumerable<T> FindDerivedTypes<T>(params object[] args) where T: class
{
List<T> objects = new List<T>();
foreach (Type type in Assembly.GetAssembly(typeof(T)).GetTypes().Where(t => t.IsClass && !t.IsAbstract && t.IsSubclassOf(typeof(T))))
{
objects.Add(Activator.CreateInstance(type, args) as T);
}
return objects;
}
}
I imagine you want to end up with something like a popup (actually a dropdown, but it's called popup here) where you see all your derived types, and once you select one of those a new instance of that type is created. You already have the types (via FindDerivedTypes
), and as all of those are after all $$anonymous$$onoBehaviours (note that won't be the same if you're working for example with ScriptableObjects), depending on what you actually want to do you'll do something like new GameObject (myType); or alreadyExistingGameObject.AddComponent (myType);
If you get the class names as strings, you should check out what the good folks at Stack Overflow have to say about it: c# instantiate class from string
If you want a list of all derrived classes as a list of references, here is a good link:
http://stackoverflow.com/questions/5045297/net-get-all-classes-derived-from-specific-class
Ins$$anonymous$$d of calling the constructor when you find the types, I would just return a list of types. You can then get the constructor for the type and invoke it when the user selects that type to be added (e.g. presses a button, or chooses from a drop-down list). (And I suggest Type.GetConstructor ins$$anonymous$$d of using Activator.)
I don't think you want to be instantiating inside that FindDerivedTypes right? That would be creating class instances every time the InspectorGUI was processed (I.e. frequently).
It looks to me like you should be returning an IEnumerable< Type> so you can create the instances later.
You can create instances if there are a constructor with parameters by using Type.GetConstructor and using Invoke on that... Use Linq to convert the parameter arrays to an array of types.
Follow this Question
Related Questions
System.Reflection types and GetConstructor issues 1 Answer
Why does Boo not see namespaces from dlls? 1 Answer
Can't call custom Debug class (assembly issue?) 2 Answers
The type or namespace name `SingletonMonoBehaviour`1' could not be found 2 Answers
Is it legal to tamper in the Assembly file libunity.so? 2 Answers