help on C# interface and its implementation

greeting guys
i am doing a simple little experiment with C# interface and i think i am stuck

here is the interface:
/////////////
using UnityEngine;
using System.Collections;

public interface changeColor_interface
{
void changeColor();

void setColorBack();
}
//////////////

and here is one of the implementation:

//////////////
using UnityEngine;
using System.Collections;

public class changeGreen : MonoBehaviour,changeColor_interface
{

private MeshRenderer gRenderer;

void Awake()
{
gRenderer = GetComponent();
}

#region changeColor_interface implementation
public void changeColor ()
{
gRenderer.material.color = Color.green;
}
public void setColorBack ()
{
gRenderer.material.color = Color.red;
}
#endregion
}
/////////////////////

then here is where i wanna call it base on the interface:

////////////////////
using UnityEngine;
using System.Collections;

public class moverColliderTriggerScript : MonoBehaviour
{

public changeColor_interface[ ] Objects;
private changeColor_interface getter;

void OnTriggerStay(Collider other)
{
if (other.GetComponent(typeof(changeColor_interface)))
{
getter = other.GetComponent(typeof(changeColor_interface));
getter.changeColor();
// other.BroadcastMessage(“changeColor”,SendMessageOptions.DontRequireReceiver);
}

}
///////////////////////////////////////////

the red line is source of the problem(without the green line), it would return error saying sth “cant implicitly convert component to #$%#”,
how come i cannot assign the type into the same type variable?

i end up using the green line (without the red line) to make this work.
but come to think about it, if i was using the green line, then what is the point of using interface at all, since broadcast message can call a specific method to be executed

IIRC you can not use GetComponent for interface types

Try wrap you code snippets you post on these forums with code tags, its much easier to read :wink:

Because GetComponent returns a Component, not a changeColor_interface. (If you would prefer to follow C# naming convention, it would be IChangeColor)

What you want is;

getter = other.GetComponent(typeof(changeColor_interface)) as changeColor_interface;

You got to cast the object you receive to the proper type.

I’m pretty sure you can. I just tried that about 10 hours ago with GetComponents with different MonoBehaviour implementing a common interface, and it did return all the different instance implementing it.

2 Likes

lightStriker , thank you for your reply, and it did work, cheers

but i am a bit confuse with this “as XXXX” at the end, coz i did specify “private changeColor_interface getter;” right from the start, which i think would make it the same type of variable as to which the type i was gonna assign, the code in my mind actually like : changeColor_interface getter = other.GetComponent(typeof(changeColor_interface));
so it seems unnecessary to add “as XXXX” at the end

now when i come to think about it, you think i can put it this way?

the interface script is never gonna be attached to any object, so its not gonna be component, but only a type class, so i hav to force it to be the type of the interface when use getcomponent, as this would return only the solid attached component!

thx again for your enlightment.

man, how do i wrap my code snippets? i am actually very new in programming and to this forum

The “GetComponent(Type type)” method is a non-generic method. It returns a specific type, and in this case, it’s “Component”.
When you call that method, what it returns is a “Component”, which is the base type of all object attached to a GameObject.

The compiler has no way to know that your interface is actually implemented by a Component. Therefore, you have to cast that variable into another type.

Let’s take the following example;

public class A { }

public interface I { }

public class B : A { }

public class C : A, I { }

In this case, “C” can be seen as being “A” or “I”.
This is perfectly acceptable;

A variableA = new C();

However, if I go the other way around, this won’t work;

// Won't work, wrong type, A is not C.
C variableC = new A(); 

// Won't work, how could we know that this variable is a C and not a A or B?
C variableC = variableA;

In GetComponents:

// works.
Component variable = GetComponent(typeof(MyComponent)); 

// doesn't work. 
MyComponent variable = GetComponent(typeof(MyComponent));

You have to force the compiler to cast that variable into a type of your choice.
There’s two way to cast a variable;

// This is an hard cast. If the value returned by GetComponent is the wrong type, an exception will be thrown.
MyComponent variable = (MyComponent)GetComponent(typeof(MyComponent)); 

// This is a soft cast. If the value returned by GetComponent is the wrong type, the cast will return null and no exception is thrown.
MyComponent variable = GetComponent(typeof(MyComponent)) as MyComponent;

You can read more about polymorphism at http://msdn.microsoft.com/en-us/library/ms173152.aspx
And about casting at http://msdn.microsoft.com/en-us/library/ms173105.aspx

http://forum.unity3d.com/threads/143875-Using-code-tags-properly

3 Likes

wow ok i learned something new today … I always thought this method did not work for finding objects via interface types

That would really suck and somewhat defeat the purpose of interfaces.

The generic overload of GetComponent constrains T to inheriting from Component. Might be what you’re thinking of?

KelsoMRK you nailed it thanks , This is where my info concerning the restriction stems from , I always just use the generic overload. I wonder why though? Why this restriction in the generic version?

Oversight? No idea.

In my mind the constraint is the more “pure” form of GetComponent so I would imagine it was intentional.

If you want to use the generic GetComponent(), you could consider rearranging your hierarchy. If all classes, which implements changeColor_interface, also inherits from MonoBehaviour, you could create an abstract change_Color class which inherits from MonoBehaviour. Your changeGreen class would then inherit from the abstract class, intstead of implementing the interface and inheriting from MonoBehaviour. The generic GetComponent<change_Color >() would then work because change_Color is a MonoBehaviour and therefore also a Component.

I think the reason the generic GetComponent() requires a component type, is that the type parameter becomes the return type. If it wasn’t constrained, GetComponent() could return something which isn’t strictly a component and perhaps that is something the unity team wants to avoid. Not sure how I feel on the issue.

Not really an oversight, just part of how generics and interfaces interact together in this instance.

A well written generic method uses constraints to communicate and enforce the intended usage of the method. Sadly there is no way to enforce “Component or any Interface” and even if they could, there is no way to enforce that interface only being used with components. It’s not possible to write a generic “GetComponent” method that works with interfaces.

For example:

public static T GetComponentUnconstrained<T>(this GameObject go) {
            return (T)go.GetComponent(typeof (T));
        }

The above code snippet does not compile because GetComponent returns a Component type, and the compiler will not allow you to attempt to cast from Component to an unconstrained type. Using “as T” instead of “(T)” would give you a different error first, you cannot use “as T” without being constrained by either :class or a specific interface. If you constrained it by either (but not a class derived from or equal to Component) you would then just get the first error again. You can do this…

public static T GetComponentUnconstrained<T>(this GameObject go) {
            return (T)(go.GetComponent(typeof (T)) as object); // You need to cast it from Component to object before the compiler will let you cast it to T
        }

Which feels like it has to be slower than GetComponent - so I tested it.

Generic for 10000000 iterations took 1.811918
Generic for 10000000 iterations took 1.83812
Generic for 10000000 iterations took 1.818989
Slow Generic for 10000000 iterations took 1.704657
Slow Generic for 10000000 iterations took 1.667595
Slow Generic for 10000000 iterations took 1.6891
Casted for 10000000 iterations took 1.47999
Casted for 10000000 iterations took 1.484753
Casted for 10000000 iterations took 1.48423

The result actually surprised me. I fully expected Slow Generic (GetComponentUnconstrained) to be noticeably slower than the usual generic. After about 10 rounds of each it seemed to actually perform faster (I realize my timing method is lazy and not as accurate as it could be, but it’s certainly accurate enough to say that the GetComponentUnconstrained method is fast enough for that rare usage where you want to GetComponent an interface).

Test code below if anyone wants to tear it apart. For what it’s worth, I did try adding a UnityEngine.Component constraint to the generic extension method and it didn’t impact the speed of it at all (leading me to believe that’s a compile time only check and does nothing at runtime probably). So the only reason I can think that the Unity provided generic is a bit slower is that they must be performing some additional, probably important logic. Maybe. /shrug

void TestGeneric(){
        float start = Time.realtimeSinceStartup;
        float end = 0;

        TestTemplateScript script = null;

        for (int i = 0; i < iterations; i++)
        {
            script = gameObject.GetComponent<TestTemplateScript>();
        }

        end = Time.realtimeSinceStartup - start;
        Debug.Log("Generic for " + iterations + " iterations took " + end);
    }

    void TestSlowGeneric(){
        float start = Time.realtimeSinceStartup;
        float end = 0;

        TestTemplateScript script = null;

        for (int i = 0; i < iterations; i++)
        {
            script = gameObject.GetComponentUnconstrained<TestTemplateScript>();
        }

        end = Time.realtimeSinceStartup - start;
        Debug.Log("Slow Generic for " + iterations + " iterations took " + end);
    }

    void TestCasted(){
        float start = Time.realtimeSinceStartup;
        float end = 0;

        TestTemplateScript script = null;

        for (int i = 0; i < iterations; i++)
        {
            script = gameObject.GetComponent(typeof(TestTemplateScript)) as TestTemplateScript;
        }

        end = Time.realtimeSinceStartup - start;
        Debug.Log("Casted for " + iterations + " iterations took " + end);
    }

They could have done

public T GetComponent<T>() where T : IComponent

public class Component : IComponent

public interface MyInterface : IComponent

Yeah… It’s maybe overkill, but it would have made that generic method possible, by deriving our own interface from IComponent.

Meh, the non-generic method works, that what is important.

In all honesty I would’ve liked to see more interface implementation with Unity.

Something like:
Updateable → implements Update() method
FixedUpdateable → implements FixedUpdate() method
etc etc

Instead of just including the method and having it “magically” work. Would at least prevent issues where people type start() instead of Start() and wonder why their stuff isn’t initialized properly. And you could do cool stuff like turn off every component that uses the physics update, etc. I understand why they did it the way they did of course.

I had a look at how the Unity3D team had implemented the generic GetComponent, using ILSpy. This is how it is implemented on GameObject.

public T GetComponent<T>() where T : Component
		{
			return this.GetComponent(typeof(T)) as T;
		}

Doesn’t look like much magic is going on.