This tool will allow you to use the [SerializeInterface] Attribute to drag and drop MonoBehaviours and ScriptableObjects.
The inspector will only accept objects that implement the correct interface.
I made this tool because [SerializeInterface] is a commonly requested features, and something I wanted in order to make code that follows SOLID principles. Serialized interface fields
It uses a Source Generator, hence classes using [SerializeInterface] will need to be made partial. It will only work in versions of Unity that support Source Generators.
I only finished making this over the last few days and still needs more testing, so please get back to me with any issues you have.
UPDATE 1:
Classes using [SerializeInterface] can now implement ISerializationCallbackReciever
Other attributes used alongside [SerializeInterface] will now also be applied to the backing object (i.e. appear in the inspector)
This is a very interesting approach to solving the interface conundrum - nice work!
Couple of potential improvement ideas that come to mind:
Attributes added to fields with the SerializeInterface attribute could be also copied over to the generated serialized fields. This way could use things like HideInInspector, Odin’s attributes etc. to control how the Object reference control should be drawn.
At the moment it’s not possible to use ISerializationCallbackReceiver and the SerializeInterface attribute at the same time. In theory it could be made possible to support this, by having the generated code implement the interface explicitly, and have it also call an implicitly implemented version in the user’s code.
public partial class Example : MonoBehaviour
{
[SerializeField] private Object example_Object;
void ISerializationCallbackReceiver.OnAfterDeserialize()
{
example = example_Object as IExample;
OnAfterDeserialize();
}
}
Plain old C# object support would of course be super nice for maximum flexibility… albeit very challenging to implement inspector-wise
and 2) are really good points and fairly easy to implement.
would be difficult and is probably outside the scope of what this should do. I wanted this feature so that it still ‘felt’ like I was coding in Unity. If you really wanted that level of flexibility, perhaps just using IoC Container is better.
In theory [SerializeInterface, SerializeReference, Inject] would still work, so long as injection is called after OnAfterDeserialize.
That makes total sense. It’s nice how simple this is at the moment - and having access to both SerializeInterface and SerializeReference already give an enormous amount of flexibility.
If this works well, How can we as a community help to get this across to everyone? Have you though about putting it on the Asset Store?
I Have yet to try it out, but it looks promising and we need like a GO TO, Asset for this problem, Maybe make a github, Open source it, and let the community make sure its always up to date for years to come. Find some code champions that can help push this.
What kind of problems can still exist from this asset, that may be looked over?
Hey Simon! Would you be willing to throw this up on GitHub as an Open Source Project? I think people would really love to help out with this solution because IMO its the most intuitive way we want to Serialize the Interface. Just to be able to add an Attribute to the Interface, and be allowed to drag serialize able types in Unity that support the interface.
I am gonna implement this in my gam jam project, Ill let you know if I run into any problems, but if its on Github We could submit pull requests, or submit issue reports.
That’s a good point, I’ve spent a couple hours today cleaning up the repo and adding documentation:
Let me know if it’s too confusing however. I think there’s a few improvements that would help a lot:
Support for [field:SerializeInterface] so we can use it on properties.
Better debugging setup. Right now there are no errors, it just works or it doesn’t.
I’m pretty sure updating the DLL will reset all of your serialized property drawers, so all editor work will be wiped out during updates. (Nevermind, it doesn’t break)
It would be cool to support plain C# classes, but that would require a dependency injection framework and would be a huge amount of work.
If you just want to use it as is, the DLL and attribute files in the Unity Project should be working.
I’m pretty sure updating the DLL will reset all of your serialized property drawers, so all editor work will be wiped out during updates.
Off thats a big one, not sure if that makes this viable or not, but it at least will get people thinking, and contributing if we can find solutions together! Thank you for all the hard work, the documentation is super nice.
It would be cool to support plain C# classes, but that would require a dependency injection framework and would be a huge amount of work.
Is there a way to have logic in the attribute to use the SerializeReference Attribute from Unity? I use a property drawer that works well with c# classes with SerializeReference.
Not sure if you can even just use one drag frop field and dynamically detect if its a unity object or a class being dragged in or selected via Unity search?
Actually I just tested an update and it doesn’t break the references. I think it only does this if the source generator itself is broken on import (but obviously you would test to make sure it isn’t before deploying).
[SerializeReference] is being used in cases where it is required (Generic Lists for example).
It would work similar to init args:
So if you selected C# mode in the UI you would get a drop down of available classes that implement the interface, and arguably choose a scope as well (Singleton, Scoped, Transient).
There would be a lightweight container and injector class behind the scenes. Of course the beauty of the source generator means it would ‘just work’ without worrying about any of that.
public class MyClass : MonoBehaviour
{
// Force the source to come from a plain C# class
[SerializeInterface(Source.CSharp)] public IFoo foo;
// Force it to be a monobehaviour / scriptable object
[SerializeInterface(Source.UnityObject)] public IBar bar;
// Choose your source via the inspector
[SerializeInterface] public IBaz baz;
}
Another ‘improvement’ would be using [SerializeField] instead of [SerializeInterface]. The Source Generator should be able to figure out the context to see if it’s applied to an interface, but that might be risky.
I would like to flesh it out one day, just too busy at the moment.