Search code examples
c#inheritancemonogame

Return nested class inherited from base class


I am working on a UI system for a MonoGame project.

I created one large class called UserInterface. Inside this class, there are nested classes such as Button, Checkbox, Scrollbar, etc. which all inherit from one base class called UIObject. Every object on the UI is stored in a private System.Collections.Generic.List<UIObject> called canvas.

The programmer using this class can easily add a new object to the canvas by using the public method UserInterface.Add(string name, UIObject obj). When the programmer adds an object to the canvas, they assign it a name so that it can be found in the list.

My problem arises as I try to make a public method that will return the object which has a specific name.

My attempt looks likes this:

public UIObject GetObject(string nameOfObject)
{
    return canvas.System.Linq.FirstOrDefault(o => o.Name == nameOfObject);
}

The issue: The object returned by this method is always a UIObject and not the inheriting class that the original object belongs to. That means it can't access the properties of the said original class. For example, if I wanted to check whether or not a Button on the canvas was pressed I would do the following:

UserInterface ui = new UserInterface();
ui.Add("nameOfButton", new Button());

if (ui.GetObject("nameOfButton").IsPressed)
{
    // Do stuff
}

However, this will not work because the property IsPressed belongs to the Button class and the returned object is a UIObject.

How can I return the objects from the canvas using their original type?

SOLVED:
Big thanks to Austin Brunkhorst for pointing me towards generics!

Working method:

public T GetObject<T>(string nameOfObject) where T : UIObject
{
    return canvas.System.Linq.FirstOrDefault(o => o.Name == nameOfObject) as T;
}

Method is called like so:

UserInterface ui = new UserInterface();
ui.Add("nameOfButton", new Button());

if (ui.GetObject<Button>("nameOfButton").IsPressed)
{
    // Do stuff
}    

Solution

  • You will need to cast the UIObject as the type you're looking to use. In this case, Button.

    Button slickButton = (Button)ui.GetObject("nameOfButton");
    

    Careful! This will throw an exception if the object is not in fact a Button.

    Alternatively, you can use the as operator, which evaluates to null if the object isn't a Button.

    Button slickButton = ui.GetObject("nameOfButton") as Button;
    

    I suggest looking into generics, as you can avoid this by explicitly stating the type you expect and have the method do the magic for you.

    Button slickButton = ui.GetObject<Button>("nameOfButton");
    

    Casting Reference