- Home /
Get a component that implements a particular interface
Hi I just found this post in the forum and I'm wondering if getting an instance of Monobehaviour
that implements a particular interface like this:
IObserver observer = GetComponent(typeof(IObserver)) as IObserver;
is a bug or a feature. It works! And I find it particularly useful.
I'm using it like this for event management:
using UnityEngine;
using System.Collections;
public class GameManager : MonoBehaviour
{
public EventDispatcher EventManager = new EventDispatcher();
// Use this to find IObservers already on the scene
void Awake ()
{
GameObject[] observers = GameObject.FindGameObjectsWithTag ("ListenerObject");
foreach(GameObject observer in observers)
{
IObserver observerBe = observer.GetComponent(typeof(IObserver)) as IObserver;
if (observerBe != null)
{
observerBe.EventManager = EventManager;
}
}
}
void Update ()
{
if(Time.time > 5)
{
EventManager.Dispatch<MoveEvent>();
}
}
}
Where the EventDispatcher
class is very similar to this one, but without the singleton part, which I personally don't like. I can post my code if anyone is interested.
The point is that this approach doesn't work with the generic version of GetComponent
,
``` IObserver observer = GetComponent(); ```
produces an error:
The type `IObserver' must be convertible to `UnityEngine.Component' in order to use it as parameter `T' in the generic type or method `UnityEngine.Component.GetComponent<T>()'
Which sounds logical, and makes the working version feel like a hack.
I've seen this particularity of the generic vs. non-generic GetComponent before, and it's pretty weird.
Note that the documentation for GetComponent specifies that it "Returns the component of Type type if the game object has one attached, null if it doesn't". Which doesn't say anything about what should happen if we ask for a Component through a Type that doesn't inherit from Component.
So the docs doesn't say which of the behaviours you are seeing is the correct one. Which means that you shouldn't count on the behaviour you're seeing in the non-generic version staying around in future updates.
It's a shame things are so unclear about this, specially when Unity's site has a tutorial about using interfaces. What's the use of them if you can't use them with your $$anonymous$$onoBehaviours? I mean if future releases might make them useless. :(
Well, I found this which might be more verbose, but it's safe in terms of future API?? changes.
Applied to the case above:
//...
void Awake ()
{
GameObject[] observers = GameObject.FindGameObjectsWithTag ("ListenerObject");
foreach(GameObject observer in observers)
{
$$anonymous$$onoBehaviour[] list = observer.GameComponents<$$anonymous$$onoBehaviour>();
foreach($$anonymous$$onoBehaviour mb in list)
{
if (mb is IObservable)
{
observerBe.Event$$anonymous$$anager = Event$$anonymous$$anager;
}
}
}
}
I found another approach using linq here,
IObserver observerBe = observer.GetComponents<$$anonymous$$onoBehaviour>.Where(c=>c is IObserver).Cast(IObserver);
I don't know whether linq behaves well with the mono libraries version Unity uses. I remember reading something about it (clai$$anonymous$$g that it doesn't and can be cause of memory leaks) but don't ask me where.