- Home /
Generic MonoBehaviour from assembly
Good day to all.
I have several scripts like
Base<Foo> : MonoBehaviour
MyScript : Base<MyScript>
All works fine, until I don't try to place them to the mono assembly.
The problem is that the only way to add this kind of scripts is to use AddComponent
in the code. And in the editor script name is empty. Don't wanna leave this solution as these scripts contain serializable fields to be set before use. It would be great if someone can help me to resolve this issue =)
Feel free to ask questions in comments. I'll update the post if it can help you to understand my problem.
Thanks at least for reading =)
EDIT: Sorry if I was unclear. IT WORKS FINE (SCRIPT MyScript
IS SERIALIZED IN EDITOR) IF I DON'T TRY TO COMPILE MY CODE TO A SEPARATE .DLL. So stop post messages like "It's impossible to serialize such scripts", please. The issue is not to serialize such kind of scripts, but to use them after compiling to a separate .dll assembly.
EDIT_2:
I had got this trouble when compiled both scripts
Base<Foo> : MonoBehaviour
MyScript : Base<MyScript>
to a separate .dll (both in the same dll, simply added to the project, not loaded at runtime). After adding compiled assembly (.dll file) to the other project, I am able to use all compiled scripts directly in editor(attach to game objects) if they(scripts) are not kind of those I mentioned above (I want anybody who uses this .dll in the project to be able to attach instance of MyScript
to any game object directly in editor). I want this dll to work with any platform, so I cannot specify it.
Hmm, it's not really clear what you mean by "place them to the mono assembly". Do you build the script manually into a seperate assembly (dll)?
yeah, there are a couple of scripts that we(me and my colleagues) wrote to make our life easier =) and we just wanna combine them to a separate .dll assembly.
Well, Unity always had problems with generic classes. Your exact setup is still not entirely clear. Are all the classes you talk about in the same assembly which you build manually? Or only the generic base class and the actual script is in another assembly?
$$anonymous$$eep in $$anonymous$$d that Unity automatically builds all scripts of one language into one or two assemblies anyways.
So which class is in which assembly? Also have you included your seperate DLL in your project or do you load the assembly at runtime? Finally what's your target platform?
Answer by Bunny83 · Jun 05, 2014 at 09:18 AM
Ok, i did again some tests (the last ones were ages ago). It's true that Unity can work with concrete classes, even when they are derived from a generic class. However Unity's DLL importer which looks for MonoBehaviour components seems to generally reject all classes that have a generic super class somewhere up the hierarchy. So while it's possible to actually use the class, the Editor won't recognise it as a valid component since no "MonoScript subasset" has been generated for that class.
This is actually a bug in Unitys DLL importer.
In the example case of a Monobehaviour-singleton there are two possible options based on if the singleton is generated on-the-fly or if it's a scene-based / serialized singleton:
If you don't need serialization, it should work out of the box. The instance is created when you first access the singleton, just as expected.
If you want to preinitialize the instance you have to create another subclass in the project itself as a dirty workaround.
Example:
// inside our external DLL
public class Singleton<TSelfType> : MonoBehaviour where TSelfType : MonoBehaviour
{
private static TSelfType m_Instance = null;
public static TSelfType Instance
{
get
{
if (m_Instance == null)
{
var type = typeof(TSelfType);
m_Instance = (TSelfType)FindObjectOfType(type);
if (m_Instance == null)
{
m_Instance = (new GameObject(type.Name)).AddComponent<TSelfType>();
}
DontDestroyOnLoad(m_Instance);
}
return m_Instance;
}
}
}
public class SomeManager : Singleton<SomeManager>
{
public string someString;
public int someInt;
public Transform someOtherObject;
}
When we import this DLL into our project, Unity won't recognise SomeManager as component. But if we add another script (SomeManagerImp.cs) to our project which contains this class:
// inside our Unity project
using OurDLLNamespace;
public class SomeManagerImp : SomeManager
{
// empty
}
We can add an instance of this class to a gameobject in the scene and have our serialized instance. The singleton still works fine since this class is a subclass of the singleton.
Thanks. I had the same result, but you had provided much more detailed description and investigation.
Answer by Loius · Jun 03, 2014 at 04:03 PM
Unity can't unity-serialize the types of generic objects. It's impossible.
I've done a few things that need types serialized, and usually I end up going with a string to represent the type (which can be selected from a drop-down if you write a custom editor / property drawer). In your case though, you might have Base : Monobehaviour and MyScript : Base, and then something stupid like BaseLogic : object which just contains the generic functions you need. A Base would create a personal instance of a BaseLogic of its own type (MyScript or Base) and link it to itself.
Dealing with Unity not serializing generics is always yucky, I'd recommend avoid needing generics of serialized Unity-types where possible (MonoBehaviour, ScriptableObject, whatever else).
It's true that Unity doesn't serialize generic types, but if you have a class that is derived from a generic $$anonymous$$onobehaviour, the class itself does serialize since the generic is buried in the class tree. You just can't use types with generic parameters directly.
So in the example if you have a variable on another script like this:
//C#
public $$anonymous$$yScript script;
and $$anonymous$$yScript is derived from a generic $$anonymous$$onoBehaviour base class it works find as long as the $$anonymous$$yScript class itself isn't a generic class.
As long as the serializer doesn't come in touch with generic classes it should work just fine. Unity uses reflection to "inspect" a class.
What would the class hierarchy look like? Not $$anonymous$$yScript : Base : $$anonymous$$onoBehaviour, since that's the one that isn't working in the question, I think.
Or is this some discrepancy between .dlls and not-dll code, perhaps?
As I'd said in my question, this code works well in case of not-dll usage. It can be serialized by editor, etc. The problem is that I want to compile all our code to the single .dll.
$$anonymous$$y understanding is that Unity cannot serialize Generic types, but it can serialize children of generic types. Basically- that this will work:
public class Singleton< T > : $$anonymous$$onoBehaviour // Cannot survive serialize cycle
public class SoundController : Singleton< SoundController > // Can survive
And that this will not work:
public class Singleton< T > : $$anonymous$$onoBehaviour // Cannot survive serialize cycle
public void SomeEditorButton() {
gameObject.AddComponent< Singleton < T > > (); // The T will be lost when reserializing
}
In the second case, Unity will be able to use the class in the run that it is made, but the class type will get lost when it tries to rebuild it. ie- it will not serialize correctly and will break between rebuilds. If you only use it at runtime, not a problem. If its alive in the editor, it will break every time you recompile. I had lots of fun trying to make a generic editor window :/
You will be probably able to see all the fields correctly in the editor when you first instantiate it, but it'll break when it goes through a serialization cycle.
Another problem you may run into (at least on iOS) is that it might crash when you try to instantiate it because the compiler couldn't tell what T would be at runtime and didn't compile one of the versions you need. For example, if you store a classname as a string then try to convert it to a type to create the instance, the binary might not contain a version of the generic for the type you need.
I have a feeling you guys might have different meanings for "Serialize". Bunny means when Unity saves it and restores it (for example, after a recompile, or when you press play), and not "It appears in the editor". However, if my understanding is slightly off and if you actually are surviving serialize cycles, then you might be running into the iOS problem.
Your answer
![](https://koobas.hobune.stream/wayback/20220613150702im_/https://answers.unity.com/themes/thub/images/avi.jpg)
Follow this Question
Related Questions
Is Reset() only called in the editor? 1 Answer
Associate a data object to Monobehaviours with generic 0 Answers
C# Inheriting from MonoBehaviour but still be able to instantiate with new()? How should I do this? 2 Answers
MonoBehaviour pseudo-singleton with C# generics 1 Answer
Generic MonoBehaviour with nested class serialization issue 1 Answer