- Home /
How to expose a field of type Interface in the inspector?
Hi,
I've found this post:
http://forum.unity3d.com/threads/49524-Exposing-fields-with-Interface-type-%28C-%29-SOLVED
but I must be missing something since I get errors!
I have an interface ISwitchableObject. Objects like lamps implement the interace. Then I have a Switch object that has a reference to an instance of an ISwitchableObject like this:
public class Switch : MonoBehaviour {
public ISwitchableObject _switchable;
}
I want to expose the _switchable field in the inspector so I can drag drop lamps and such to it. I've tried doing the below but it gives me errors (says I have invalid arguments). What am I doing wrong?
Thanks
[CustomEditor (typeof (Switch))]
public class SwitchInspector : Editor
{
void OnInspectorGUI ()
{
Switch s = (Switch)target;
s._switchable = EditorGUILayout.ObjectField ("switchable", s._switchable, typeof (ISwitchableObject));
DrawDefaultInspector ();
}
}
You could make the _switchable field into an Object (or perhaps Component), then use your custom editor to make sure only Objects implementing ISwitchableObject can be assigned by the user.
Answer by Roland1234 · Oct 29, 2013 at 03:04 AM
Unity, by itself, does not expose fields that are of an interface type. It is possible to manually enable this functionality by implementing a custom inspector each time as Mike 3 has pointed out, but even then the reference would not be serialized ("remembered" between sessions and entering/exiting playmode).
It is possible however to create a serializable container object that wraps around a Component field (which is serialized) and casts to the desired interface type through a generic property. And with the introduction of custom property drawers into Unity, you can effectively expose a serialized interface field in your scripts without having to write a custom inspector / property drawer each time.
I've taken this approach and released an asset that does exactly that here, for anyone who's interested.
Answer by fresch1990 · Feb 27, 2020 at 03:04 PM
This might be irrelevant by now but jsut if someone still have the same issues:
Just add the Attributes:
[SerializeField, SerializeReference]
private IState currentState;
That just worked for me, Cheers!
I hope this will help someone. @mat
The field is displayed after adding these attributes but is not available for drag and drop. Unable to set the reference from the inspector. Am I missing something? (tested in Unity 2020.2.0f1 and 2019.4.17f1 LTS)
Yep, just discovered the same thing with 2019.4.14f1. Seems to not work.
as is the case with @alarion24 , the field is not available for drag and drop; only the name of the field in shown in the inspector (using Unity 2020.2f)
Answer by Endar · Mar 01, 2018 at 03:33 PM
One way to do it is using a Component
variable for what is displayed in the inspector, and a second variable of the interface that is set using the first on Start
or Awake
. Using the OnValidate
method, you can have it check if the Component variable is of the interface, i.e. if (component is interface)
. If it fails that, you have it set the component to null
. Example
public Component movement;
protected iMovement motor;
protected void OnValidate()
{
if (!(movement is iMovement))
movement = null;
}
protected override void Awake()
{
if (movement != null)
motor = (iMovement)movement;
}
This is not a perfect solution. You have to set the component to the exact component you want to use.
Answer by lgarczyn · Mar 08, 2017 at 01:18 AM
There's an answer that no one has suggested yet:
Instead of declaring an interface like so
public interface IDoable {
void DoIt();
}
public class Doer : MonoBehaviour, IDoable {
public void DoIt();
}
public class DoableContainer : MonoBehaviour {
public IDoable doable;
}
just do
public abstract class ADoable : MonoBehaviour{
virtual void DoIt();
}
public class Doer : ADoable {
public void DoIt();
}
public class DoableContainer : MonoBehaviour {
public ADoable doable;
}
Your Doer can only implement one "interface", and all your implementation of Doable have to inherit from the same class (here MonoBehaviour), but it works, is displayed, and is saved with little additional cost;
Interface implementation and class inheritance may both be seen as accomplishing polymorphism, but they're really not the same things. An interface defines what an object can do, and inheritance defines what an object is.
You're right to suggest that Unity will serialize base class references, although there a few gotchas in that as well: the referenced type cannot have unresolved generic type parameters, and if you're dealing with non-Unity.Object serializable types I seem to remember Unity will forget the derived type on the next serialization cycle (in fact, I swear I saw Unity instantiate an abstract type playing around with this once, which is all sorts of messed up).
Oh, and the virtual keyword is not a class modifier and does require a method body, you were likely thinking of abstract in your example.
But cheers for the suggestion, it is an option as far as polymorphism goes.
Changed the "virtual" ins$$anonymous$$d of "abstract", my c++ days somehow got mixed in, thanks for the correction.
Interface implementation is however not that far from inheritance. Back in c++, when you could inherit from multiple classes, interfaces where just fully abstract classes.
Changing "inherit from A implement abstract B" to "inherit from abstract B that inherits from A" is essentially the same thing (if unity does its job correctly).
I know this is a bit old but i want to make sure it is a bit clear for anyone who doesn't quite understand the differences between base classes and interfaces. A C# class can only be derived from 1 base class. Every class (unless explicitly deriving from another class) derives from the class object
. To overcome this limitation, a class may implement any number of interfaces.
An interface is a contract. meaning that when you create a variable of type IMyInterface
it is guaranteed to have all the members and methods of that interface. So you can safely pass it around as if it was it's own data type and what ever class actually makes up that implementation is irrelevant. Interfaces is the tooling that allows dependency injection. You can have many different implementations of the same interface, and at runtime replace them with one another. For unity, you can have one that is done in the editor, one for debugging, and yet another for your release, all without refactoring the other systems that consume the interface.
If it would be limited to a single interface this would be same as class inheritance and that would be easier to maintain that way. Unfortunately this does not have much value without multiple inheritance support.
I was confused by using abstracts and inheritances instead of interfaces but you can achieve the same effect with abstracts and inheritances, i.e. in the above sample you can create different Doer classes and override the ADoable as many times as you want, then reference the ADoable which is a parent class in your main class (DoableContainer), this will let you input either of your Doer overrides as you wish without the need to change anything. This absolutely works, don't worry.
Answer by vexe · Sep 05, 2014 at 05:50 PM
I've answered this in-depth here: http://answers.unity3d.com/questions/783456/solution-how-to-serialize-interfaces-generics-auto.html
Checkout ShowEmAll: Serialize interfaces, generics, auto-properties, dictionaries, abstracts, etc.
Your answer
Follow this Question
Related Questions
Component OnAwake or OnEnable with PropertyAttribute 1 Answer
Fields using Struct not showing up in Inspector. 1 Answer
Is there any way to change order of inherited fields in inspector? 0 Answers
Exposing interface implementation 3 Answers
expose public property (not variable) in inspector 9 Answers