You can of course solve this in different approaches where one is inheritance by a base class, another one is your interface approach (which is inheritance btw. too) and you could also work in an ECS like environment. It is up to you what fits best.
I would use the ECS approach and simply add an Entity to the list for everything you want to display, that have components for all the data (an Icon-Component and Building-Component) but you also can use the interface approach if you don't want to inherit everything from a common base class.
Usually you have a kind of database that creates those objects for you rather than defining them in code. It has the advantage to not change the code every time you want to add/remove or change an existing building/unit/resource/whatever.
Finally it depends what environment you are using/ which and if you are using a game engine. Unity has ECS built-in but as you wrote you work in VisualStudio, I assume you are using plain C# and so have access to the DLR and Reflection. So I describe too approaches I use in my code that are based on the ECS model, because of two reasons:
- You don't need to define data instances in every class rather than maintain it's components and reduce initialization complexity
- You can handle instances differently depending on their components
If you want to run a simple ECS approach for example, you need to identify your classes as entities. I do this by an interface (IEntity) that my classes inherit and provide an EntityId, that is set by the class. Then I maintain dictionaries for each ComponentType and simply perform a lookup if a ComponentId exists that matches my Entity. Put all this together into some extension methods so I have AddComponent, GetComponent and RemoveComponent on any class that inherits from IEntity. As entities are defined as a single ID, you can also reference to an existing entity by a component without knowing the entity itself.
The other approach I tried (successfully) is utilizing the capabilities of the DLR (dynamic language runtime) which are used in dynamic objects. This is a wrapper around some CLR related type definition code allowing to dynamically set and get properties of an object at runtime without defining those properties in beforehand. An example:
class CourtHouse
{
public int AmountOfRooms { get; private set; }
public CourtHouse(int amountOfRooms)
{
this.AmountOfRooms = amountOfRooms;
}
}
dynamic myLargeCourtHouse = new CourtHouse(15);
myLargeCourtHouse.Icon = new Bitmap("<asset path>");
myLargeCourtHouse.ConstructionTime = 50;
myLargeCourtHouse.Cost = new ResourceIdentifier(ResourceType.Money, 10000);
What this code does is initializing an instance of a simple class in C# and utilizing the DLR to add dynamic properties to the class which can be of any type and any name.
Making use of this for an ECS can be as simple as try/catch test for properties or you can override DynamicMetaObject and provide your own Binder instance that feeds your ECS system in the background. Take care as this is a lot of try/error until it fully works but you can achieve a level of dynamic objects that are far beyond those the runtime offers by default.
In our SDKs Compound Package we are doing exactly this to be able to add dynamic properties to our objects, dynamic functions and even dynamic inheritance of interfaces !at runtime!. The package is not meant to be an ECS but help us write classes to be used in our Editor code to primary fit into necessary interface definitions. But it can be even used in an ECS environment as everything can be tested for and we have Try-methods for it