- Home /
problem with interface and abstract class in unity
Hello, There is a problem I always face. If I use interface I cannot use drag/drop in editor. Also, FindObjectsOfType doesn't work because it is not an object. There is the same problem when I use abstract class. Is there any solution?
Can you show us your code for the FindObjectsOfType
Let me write an example like that:
public interface ITryInterface { void $$anonymous$$y$$anonymous$$ethod(); }
public class TryClass1: $$anonymous$$onoBehaviour, ITryInterface{ void $$anonymous$$ethod(){ //Do Something cool } }
public class TryClass2: $$anonymous$$onoBehaviour, ITryInterface{ void $$anonymous$$ethod(){ //Do Something cooler } }
public class TryClass3: $$anonymous$$onoBehaviour, ITryInterface{ void $$anonymous$$ethod(){ //Do the coolest! } }
public class $$anonymous$$anager:$$anonymous$$onoBehaviour{ public ITryInterface[] try; /cannot drag, drop. Can't see in the editor and con't find them with findobjectoftype/
void Start(){
foreach(ITryInterface item in try){
item.$$anonymous$$ethod();
}
}
}
public abstract class TryClass: $$anonymous$$onoBehaviour{ abstract public void $$anonymous$$ethod(); }
public class TryClass1: TryClass { override public void $$anonymous$$ethod(){ //Do Something cool } }
public class TryClass2: TryClass { override public void $$anonymous$$ethod(){ //Do Something cooler } }
public class TryClass3: TryClass { override public void $$anonymous$$ethod(){ //Do the coolest! } }
public class $$anonymous$$anager:$$anonymous$$onoBehaviour{ public TryClass[] try; /cannot drag, drop. Can't see in the editor and can't find them with findobjectoftype/
void Start(){
foreach(TryClass item in try){
item.$$anonymous$$ethod();
}
}
}
I don't know how to share as a script. Sorry
Answer by Bunny83 · Jul 18, 2017 at 12:36 AM
Of course you can't use an interface in this case since Unity can only serialize references of types which are derived from UnityEngine.Object. However an abstract class which is derived from MonoBehaviour works just fine. I just created an example in my test project just like yours and it works just fine. I created 3 files TryClass, TryClass1 and Manager
// TryClass.cs
public abstract class TryClass : MonoBehaviour
{
public abstract void MyMethod();
}
// TryClass1.cs
public class TryClass1 : TryClass
{
public override void MyMethod()
{
Debug.Log("TryClass1");
}
}
// Manager.cs
public class Manager : MonoBehaviour
{
public TryClass[] list;
void Start()
{
foreach (var c in list)
c.MyMethod();
}
}
Answer by ZeN12 · Jul 18, 2017 at 07:15 AM
First option, class should inhered from MonoBehavior (or Component, not sure about this).
Second option, class (or struct) should be serializable.
https://docs.unity3d.com/ScriptReference/Serializable.html
Answer by UnityCoach · Jul 20, 2017 at 03:39 PM
This is a topic I touched on in my SOLID design training course. FindObjectOfType doesn't work with interfaces, though GetComponent does.
So, here's something you can do is :
1) find all root objects, using System.Linq
to filter all transform with no parent
List<Transform> rootTransforms = (from t in FindObjectsOfType<Transform>()
where t.parent == null
select t).ToList();
2) then use GetComponentsInChildren<Interface>()
on them.
List<ISpecialEventHandler> _specialEventHandlers = new List<ISpecialEventHandler>();
foreach (Transform t in rootTransforms)
_specialEventHandlers.AddRange (t.GetComponentsInChildren<ISpecialEventHandler>());
It's true that unfortunately FindObjectsOfType doesn't accept an interface however it does work just fine with an abstract base class that is derived either from $$anonymous$$onoBehaviour or ScriptableObject.
Ps: Since in your solution FindObjectsOfType<Transform>()
already returns an array with all Transform components, it doesn't make much sense to throw most of them away and then use GetComponentsInChildren. GetComponentsInChildren has to iterate through the whole hierarchy of the given object. Since you already have all Transform components you can just use GetComponents on each Transform.
However a better approach would be to use FindObjectsOfType<$$anonymous$$onoBehaviour>()
and just as-cast all of them to your interface. That way you can avoid all the additional GetComponents / GetComponentsInChildren. There are most likely much more Transform components out there than $$anonymous$$onoBehaviour derived Components.
With Linq you could simply do:
var list = FindObjectsOfType<$$anonymous$$onoBehaviour>().OfType<ISpecialEventHandler>().ToList();
This does only allocate memory for the initial "$$anonymous$$onoBehaviour[]" array and the final List (and of course the temporary linq IEnumerables / IEnumerators).
"OfType" basically does two things in one: .Select(c=>c as ISpecialEventHandler).Where(c=>c != null)
Interesting. I figured GetComponentsInChildren would probably be "optimised" and provide better results than casting every single $$anonymous$$onoBehaviour. I guess we can predict which of FindObjectsOfType<$$anonymous$$onoBehaviour>()
and FindObjectsOfType<Transform>()
will be the smaller, depending on the scene configuration. I'll do some testing on my scene. Thanks for the tip!
Your answer
Follow this Question
Related Questions
How to Store and Reference Skills Flexibly? 0 Answers
Multiple Cars not working 1 Answer
Class derivation problem 1 Answer
Distribute terrain in zones 3 Answers
An OS design issue: File types associated with their appropriate programs 1 Answer