I am using a component system for certain Objects(just like components in Unity). Each component inheriths from the class Component. The objects then have a list of components.
What I am trying to implement is a GetComponent() method. It returns the component of type T if it exists, otherwise it returns null. Let's say that an Object has the Renderer Component. I want to be able to call the Draw method in the Renderer class:
Object.GetComponent<Renderer>().Draw();
The problem is that when I call this function I get the parent class(of type: Component) instead of the child class. Because of that, when I try the code above ^^ I get the error; 'Component' does not contain a definition for 'Draw' (...)
Code:
internal abstract class GameObject : Object
{
//Props
public string name;
public GameObject? parent;
public Transform transform
{
get
{
return (parent == null) ? transform : parent.transform;
}
private set
{
transform = value;
}
}
public bool isActive = true;
private List<Component> components = new List<Component>();
//Constructer
public GameObject(string name, GameObject? parent = null)
{
this.name = name;
transform = new Transform(this);
components.Add(transform);
this.parent = parent;
}
public void AddComponent(Component component)
{
components.Add(component);
}
//Method that is not working properly
public Component GetComponent<T>()
{
foreach (Component component in components)
{
if (typeof(T) == component.GetType())
return component;
}
return null;
}
}
}
CodePudding user response:
Instead of returning Component, return T. Also, use is for type checking and casting:
public T GetComponent<T>() where T : Component
{
foreach(var component in components)
{
if(component is T value) return value;
}
return default;
}
BTW, what if you have two components of the same type? You might want to consider using Linq's OfType<T>() here instead of a foreach.
CodePudding user response:
The return value of the method needs to be T
public T GetComponent<T>()
{
// your code
}
GetComponent<Renderer>().Draw() is 2 statements
GetComponent<Renderer>()Draw()
By writing it like so:
// 'component' is of type 'Component' here, not 'Renderer'
var component = GetComponent<Renderer>();
component.Draw();
It's obvious why it doesn't work with your current code and why it does with the updated one.
P.S I'd personally also add a constraint to make sure we can only GetComponent<T> with types that actually are components, like so:
public T GetComponent<T>() where T : Component
{
}
With the where we're forcing compile time checks that this method can only be called with types that inherit from Component
