Using GetComponent with base classes

I have a weird problem where I’m trying to access a component inside a gameobject by referencing its base class which is only returning a null. Here’s how I’m trying to access my component.

m_attachment = m_heldObject.GetComponent< BaseAttachment<BaseMusicObject> >();

In this situation, the actual component is of type InstrumentAttachment which extends BaseAttachment. The class is set up like this.

public class BaseAttachment<T> : MonoBehaviour where T : BaseMusicObject 
{ 
    protected T m_musicRef;
    public virtual T musicRef{ get { return m_musicRef;}
    
    public virtual void Init(T managedReference){
        m_musicRef = managedReference;
    }
}

InstrumentAttachment is initialized as a InstrumentAttachment object so that musicRef can be returned with the same type the generic class is initialized as. BaseInstrument extends BaseMusicObject. InstrumentAttachment is set up in this way.

public class InstrumentAttachment : BaseAttachment<BaseInstrument>{
}

Using GetComponent( typeOf(BaseAttachment < BaseMusicObject > ) ) as BaseAttachment < BaseMusicNote > ; will also fail, but accessing the component with its derived type using GetComponent() will work.

Am I doing something horribly wrong?

I’m not 100% sure that you are being affected by this, but I suspect that you are making use of covariance and contravariance in generic types and those features were incorporated first into C# 4.0.

As far as I know, Unity uses C# 3.0.

Have a look at this: Covariance and Contravariance

I managed to work around this problem by having a non-typed abstract class as the base class.

GetComponent< BaseAttachment>() now works since derived classes all have a common ancestor to work from.

Base Classes:

public abstract class BaseAttachment : MonoBehaviour
{
    public virtual void foo()
    {
    }
}

public class BaseAttachment<T> : BaseAttachment
{
	protected T m_musicRef;
	public void Init(T managedReference){
		m_musicRef = managedReference;
	}
	public T musicRef{ get { return m_musicRef; }}
}

Derived class:

public class InstrumentAttachment : BaseAttachment<BaseInstrument>{
    public override void foo()
    {
    }
}

This lets me run my overridden functions from any class derived from BaseAttachment, but offers me the ability to return the correctly typed musicRef object if working with the derived class.

Eg:

GameObject instrument = new GameObject();
instrument.AddComponent<InstrumentAttachment>().Init( new BaseInstrument() );

//Runs overridden foo
instrument.GetComponent<BaseAttachment>().foo();      

//Runs overridden foo     
instrument.GetComponent<InstrumentAttachment>().foo();     

//Returns BaseInstrument
instrument.GetComponent<InstrumentAttachment>().musicRef;