Wayback Machinekoobas.hobune.stream
May JUN Jul
Previous capture 14 Next capture
2021 2022 2023
3 captures
13 Jun 22 - 14 Jun 22
sparklines
Close Help
  • Products
  • Solutions
  • Made with Unity
  • Learning
  • Support & Services
  • Community
  • Asset Store
  • Get Unity

UNITY ACCOUNT

You need a Unity Account to shop in the Online and Asset Stores, participate in the Unity Community and manage your license portfolio. Login Create account
  • Blog
  • Forums
  • Answers
  • Evangelists
  • User Groups
  • Beta Program
  • Advisory Panel

Navigation

  • Home
  • Products
  • Solutions
  • Made with Unity
  • Learning
  • Support & Services
  • Community
    • Blog
    • Forums
    • Answers
    • Evangelists
    • User Groups
    • Beta Program
    • Advisory Panel

Unity account

You need a Unity Account to shop in the Online and Asset Stores, participate in the Unity Community and manage your license portfolio. Login Create account

Language

  • Chinese
  • Spanish
  • Japanese
  • Korean
  • Portuguese
  • Ask a question
  • Spaces
    • Default
    • Help Room
    • META
    • Moderators
    • Topics
    • Questions
    • Users
    • Badges
  • Home /
avatar image
19
Question by tylo · Mar 11, 2011 at 01:06 AM · inheritancecustom-inspector

Do Custom Inspectors Support Inheritance?

Let's say I have the following hierarchy set up:

BaseClass -> MyClass

If I make a custom inspector for BaseClass, can I get it to display for MyClass?

Comment
Add comment
10 |3000 characters needed characters left characters exceeded
▼
  • Viewable by all users
  • Viewable by moderators
  • Viewable by moderators and the original poster
  • Advanced visibility
Viewable by all users

6 Replies

· Add your reply
  • Sort: 
avatar image
55
Best Answer

Answer by sproinkalonk · Sep 01, 2013 at 02:44 PM

I'm not sure if/when this was changed, but you can explicitly tell Unity to use a particular Editor for inherited classes:

http://docs.unity3d.com/Documentation/ScriptReference/CustomEditor-ctor.html

e.g.

 [CustomEditor( typeof( BaseClassName ), true )]

Hope this helps!

Comment
Add comment · Show 5 · Share
10 |3000 characters needed characters left characters exceeded
▼
  • Viewable by all users
  • Viewable by moderators
  • Viewable by moderators and the original poster
  • Advanced visibility
Viewable by all users
avatar image whydoidoit · Dec 19, 2013 at 06:43 PM 1
Share

It was changed in 4.1 I believe.

avatar image John-LZG · Feb 19, 2014 at 09:08 AM 0
Share

This does enable it to be used for derived classes, but how do you tell what derived class you have from the SerializedProperty?

avatar image rakkarage · Apr 29, 2016 at 05:39 PM 1
Share

can use the is keyword to check

avatar image rodude123 rakkarage · Apr 29, 2016 at 05:41 PM 0
Share

not sure but you can check out the link above to find out

avatar image Qvepoy · Oct 13, 2021 at 09:12 AM 0
Share

Thank you very much!

avatar image
11

Answer by .sanders · Jan 20, 2012 at 07:11 PM

Well you can fix this easily by overwriting the OnInspectorGUI() in your BaseClass. If I were you I'd create a BaseClassEditor script which is the CustomEditor for the BaseClass and a MyClassEditor script which inherits from BaseClassEditor. To put it in your example:

 // C#
 [CustomEditor(typeof(BaseClass))]
 public BaseClassEditor : Editor
 {
     public override void OnInspectorGUI()
     {
         // Put YOUR custom inspector code here for the base class
     }
 }
 
 [CustomEditor(typeof(MyClass))]
 public class MyClassEditor : BaseClassEditor
 {
     public override void OnInspectorGUI()
     {
         base.OnInspectorGUI();
         // Additional code for the derived class...
     }
 }

This should work just fine. (not tested myself but am about to...) Hope this is what you're looking for...

Of course you NEED to define the [CustomEditor(typeof(MyClass))], if not unity will draw the default inspector even if you have a CustomEditor for the base class..

cheers!

Comment
Add comment · Show 10 · Share
10 |3000 characters needed characters left characters exceeded
▼
  • Viewable by all users
  • Viewable by moderators
  • Viewable by moderators and the original poster
  • Advanced visibility
Viewable by all users
avatar image The-Oddler · Jan 20, 2012 at 09:03 PM 0
Share

I love this, can't test it right now myself, but please do tell when you tested it!

avatar image .sanders · Jan 21, 2012 at 08:36 PM 0
Share

Yes, tested it out and works perfectly!

avatar image ammirea .sanders · Mar 21, 2019 at 10:53 AM 0
Share

It works only in some cases. Read my comment.

avatar image The-Oddler · Jan 21, 2012 at 09:09 PM 0
Share

Awesome! I always thought it was impossible, thanks!

avatar image Matheuz · Mar 11, 2015 at 09:18 PM 0
Share

Does anyone know how I can replicate this behaviour with Property Drawers? I tried to but it acts like the child's OnGUI call is being ignored.

avatar image DKasper_3DQR · Feb 15, 2017 at 10:12 AM 0
Share

Did somebody encounter the problem of the OnInspectorGUI() function not getting called when implementing custom editors with inheritance like this? I do and altough the display of the custom inspector works the OnInspectorGUI() never gets called and so no changes are made to the corresponding variables although i changed them in the inspector.

avatar image angralon DKasper_3DQR · Feb 26, 2017 at 12:11 PM 0
Share

@D$$anonymous$$asper_3DQR: I had to use serializedObject.Apply$$anonymous$$odifiedProperties(); to make my changes to the variables apply. Not sure if this is your issue though.

avatar image DKasper_3DQR angralon · Feb 27, 2017 at 07:14 AM 0
Share

For me the mistake was that I unintentionally wrote the type of the editor into [CustomEditor(typeof()) because it almost has the same name as the class for which i wrote it. But I oversaw this several times.

Show more comments
avatar image
7

Answer by whydoidoit · Dec 19, 2012 at 09:37 PM

I ran into this and you can make it work without having to write a custom inspector for every derived class - not sure how wise it is, but this works in U3/U4 - certainly totally undocumented :)

 using UnityEngine;
 using System.Collections;
 using UnityEditor;
 using System;
 using System.Reflection;
 using System.Linq;

 
 [InitializeOnLoad] //Make sure this code runs every time the editor is updated
 public class MagicInspectors : EditorWindow {
 
     
     static MagicInspectors()
     {
             //Get access to the UnityEditor assembly
         var asm = Assembly.GetAssembly(typeof(UnityEditor.CustomEditor));
             //Use Linq to find the CustomEditorAttribute type
         var cea = asm.GetTypes().FirstOrDefault(t=>t.Name == "CustomEditorAttributes");
             //Get access to the method that is called to find a custom editor for a type - this 
             //caches the results, so it has to happen before we play with the lists
         var findCustomEditor = cea.GetMethod("FindCustomEditorType", BindingFlags.Static | BindingFlags.Public | BindingFlags.NonPublic);
             //Call it
         findCustomEditor.Invoke(null, new object [] { new UnityEngine.Object(), false });
             //Find the MonoEditorType class so we can make instances of it later
         var next = asm.GetTypes().FirstOrDefault(t=>t.Name .Contains("MonoEditorType"));
         var inst = Activator.CreateInstance(next);
             //Get the field in that class which is the type of the inspector to use
         var inspectorType = next.GetField("inspectorType");
             //Get the field in that class which is the type to inspect using this inspector
         var inspectedType = next.GetField("inspectedType");
             //Get the custom editors field which is the cache in CustomEditorAttribute
         var editorsField = cea.GetField("m_CustomEditors", BindingFlags.Static | BindingFlags.NonPublic);
             //Get the current list (it's an ArrayList)
         var editors = editorsField.GetValue(null) as ArrayList;
             //Get the current list of multi item editors
         var multiEditorsField = cea.GetField("m_CustomMultiEditors", BindingFlags.Static | BindingFlags.NonPublic);
         var multiEditors = multiEditorsField.GetValue(null) as ArrayList;
         
             //Now its time to get all of the inspectors we've defined
         //Get all of the current assemblies loaded
         var types = AppDomain.CurrentDomain
             .GetAssemblies()
                     //Get all of the types in those assemblies
             .SelectMany(a=>a.GetTypes())
                     //Which have a CustomEditor attribute
             .Where(t=>t.IsDefined(typeof(CustomEditor), true))
                     //Get the type that this CustomEditor edits
             .Select(t=>new { editor = t, inspected = (Attribute.GetCustomAttribute(t, typeof(CustomEditor), false) as CustomEditor).m_InspectedType}).ToList();

             //Now look for types that are the type edited or its subclasses
         var usableTypes = AppDomain.CurrentDomain
             .GetAssemblies()
             .SelectMany(a=>a.GetTypes())
                     //For all of the types, get the custom inspector for which they are assignable
                     //In other words find an inspector (or null) for which this type can be downcast to
             .Select(t=>new { editable = t, custom = types.FirstOrDefault(e=>e.inspected.IsAssignableFrom(t)) })
                     //Make sure we only have valid ones
             .Where(r=>r.custom != null);

             //Now update the internal cache with these new types

         foreach(var newEditor in usableTypes)
         {
                     //Create a new instance of the internal structure that represents the relationship
             var editorInstance = Activator.CreateInstance(next);
                     //tell it which inspector to use
             inspectorType.SetValue(editorInstance, newEditor.custom.editor);
                     //tell it which type to inspect from the list we made above
             inspectedType.SetValue(editorInstance, newEditor.editable);
                     //Add it to multiEditors if it supports it
             if(newEditor.custom.editor.GetType().IsDefined(typeof(CanEditMultipleObjects), false))
                 multiEditors.Add(editorInstance);
                     //Add it to ordinary editors always
             editors.Add(editorInstance);
         }
         
         
     }
     
 }
 
Comment
Add comment · Show 11 · Share
10 |3000 characters needed characters left characters exceeded
▼
  • Viewable by all users
  • Viewable by moderators
  • Viewable by moderators and the original poster
  • Advanced visibility
Viewable by all users
avatar image trey@drixel · Feb 04, 2013 at 01:05 AM 0
Share

I have no idea what this code is doing, but it works. This is the solution to this problem, as far as I can see. I'd upvote it, but I'm a mere peasant on this site.

avatar image trey@drixel · Feb 04, 2013 at 01:08 AM 0
Share

Note: the variable inst on line 19 is never used.

avatar image The-Oddler · Feb 04, 2013 at 10:22 AM 0
Share

This looks like very interesting code. There are some methods you use of which I'm not entirely sure what they do. Would you $$anonymous$$d adding some comments to explain what's happing? Thanks!

avatar image whydoidoit · Feb 04, 2013 at 10:24 PM 1
Share

Sure :) I can do that -

Basically what it is doing is using the messing with the list of Editors Unity has already figured out for a project and adding the ones where the type is derived from an editable type.

Lines 17 & 19 in the code are forcing Unity to do its caching before we mess with the results! Internally Unity does this only once per load of the code - so if it's done it - it won't again. This class is marked InitializeOnLoad so it will be called immediately the editor is loaded or updated.

Internally Unity has a $$anonymous$$onoEditorType class that associates a class with a custom editor - as we all know that only happens for specific types and not their derivatives. So we go ahead, scan all the types, find the derivatives and add them as well.

To do that we have to access some classes that are marked as internal, so a lot of the code is using reflection to do just that - if Unity changes the names of any of those internal properties or fields then it would break - they haven't done that in a while, so I'm hoping it's good for the long term.

(Note you can also use tricks like this with internal .NET classes. That technique lets my Unity Serializer save the current state of a coroutine and resume it later after the game has been reloaded from a server or player prefs etc etc)

I'll comment the code.

avatar image whydoidoit · Feb 04, 2013 at 10:36 PM 0
Share

BTW I used DotPeek to look at how the existing Unity code works which let me find out the names and types of everything.

Show more comments
avatar image
0

Answer by dago23 · Feb 08, 2012 at 07:10 PM

This doen't work in my case. I have a custom monobehaviour, let's say MyMonoBehaviour derived from MonoBehaviour. Users should be able to derive their new scripts from MyMonoBehaviour.

In the inspector I want to add some Buttons that belong to MyMonoBehaviour.

Problem is, I can not force users to write a custom inspector for their scripts and to call the base class inspector!

So is there any way to achieve my goal either? I don't see one at the moment. It would work if the default Inspector would call it's base class inspectors. But unfortunately it seems not to do that?

Any ideas?

Comment
Add comment · Show 4 · Share
10 |3000 characters needed characters left characters exceeded
▼
  • Viewable by all users
  • Viewable by moderators
  • Viewable by moderators and the original poster
  • Advanced visibility
Viewable by all users
avatar image .sanders · Feb 08, 2012 at 08:29 PM 0
Share

Sure: remove the virtual keyword (you CAN also make it protected) from the definition of the OnInspectorGUI() so that your users can't override it and simply define a new virtual or abstract method which you call from the OnInspectorGUI() body and that users can override.. that way you guarantee that your inspector is called first and after that the additional content. Example:

[CustomEditor(typeof(BaseScript))] public abstract class BaseScriptEditor : Editor { protected abstract void OnDerivedInspectorGUI(); private void OnInspectorGUI() { // do YOUR custom stuff here OnDerivedInspectorGUI(); } }

Then you need to inform the users to override the OnDerivedInspectorGUI(). Of course you can't prevent the users from defining their own OnInspectorGUI() in this solution but when they first try to do that they will get a compiler warning that says it hides the OnInspectorGUI() of the base class (that's why it's protection level should be public or protected). So they will have some kind of notification. Of course they can remove the warning by adding the new keyword to their implementation but then they chose willingly to do so, at least they can't accidentally overwrite it or forget to call the base's OnInspectorGUI()

I don't think there is a more elegant solution to this problem than the one I mention here.

cheers

avatar image dago23 · Feb 09, 2012 at 08:16 AM 0
Share

thanks, but that doesn't help in my case The private OnInspectorGUI is never called if it belongs to a base class.

And as I said, I don't want to force users to write an inspector.

avatar image .sanders · Feb 09, 2012 at 01:05 PM 0
Share

hmm did not know that, thought it would work. If I have some time today I'll try some things out!

avatar image dago23 · Feb 09, 2012 at 05:15 PM 0
Share

thanks again, but I think there is no way. Tried the whole day ;)

avatar image
0

Answer by ematsuno · Mar 11, 2019 at 06:33 PM

it' 2019, my research corroborates the findings, It doesn't work out of the box as you would hope. The workarounds appear possible, but more complicated than worth the effort and probably less stable.

The compiler does not like this solution: [CustomEditor(typeof(BaseScript))] public abstract class BaseScriptEditor : Editor { protected abstract void OnDerivedInspectorGUI(); private void OnInspectorGUI() { // do YOUR custom stuff here OnDerivedInspectorGUI(); } } but it does look quite compelling, but the warnings bug me ;)

There are alternative ways to make it customizable as well, Copy/paste seems more stable for the kind of complexity I need at the moment unless there's a better solution...

Comment
Add comment · Share
10 |3000 characters needed characters left characters exceeded
▼
  • Viewable by all users
  • Viewable by moderators
  • Viewable by moderators and the original poster
  • Advanced visibility
Viewable by all users
  • 1
  • 2
  • ›

Your answer

Hint: You can notify a user about this post by typing @username

Up to 2 attachments (including images) can be used with a maximum of 524.3 kB each and 1.0 MB total.

Follow this Question

Answers Answers and Comments

20 People are following this question.

avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image

Related Questions

C# unity custom editor multiple different components but same base class 2 Answers

An OS design issue: File types associated with their appropriate programs 1 Answer

Generic CustomEditor 0 Answers

Building a Collection of Subclasses and Modifying Their Public Members from the Inspector 0 Answers

Can a class's Editor call its component's Editor? Likewise, can a derived class's Editor call its base class's Editor? 1 Answer


Enterprise
Social Q&A

Social
Subscribe on YouTube social-youtube Follow on LinkedIn social-linkedin Follow on Twitter social-twitter Follow on Facebook social-facebook Follow on Instagram social-instagram

Footer

  • Purchase
    • Products
    • Subscription
    • Asset Store
    • Unity Gear
    • Resellers
  • Education
    • Students
    • Educators
    • Certification
    • Learn
    • Center of Excellence
  • Download
    • Unity
    • Beta Program
  • Unity Labs
    • Labs
    • Publications
  • Resources
    • Learn platform
    • Community
    • Documentation
    • Unity QA
    • FAQ
    • Services Status
    • Connect
  • About Unity
    • About Us
    • Blog
    • Events
    • Careers
    • Contact
    • Press
    • Partners
    • Affiliates
    • Security
Copyright © 2020 Unity Technologies
  • Legal
  • Privacy Policy
  • Cookies
  • Do Not Sell My Personal Information
  • Cookies Settings
"Unity", Unity logos, and other Unity trademarks are trademarks or registered trademarks of Unity Technologies or its affiliates in the U.S. and elsewhere (more info here). Other names or brands are trademarks of their respective owners.
  • Anonymous
  • Sign in
  • Create
  • Ask a question
  • Spaces
  • Default
  • Help Room
  • META
  • Moderators
  • Explore
  • Topics
  • Questions
  • Users
  • Badges