c# trying not to repeat myself - inheritance and strong typing issues

I have two dictionaries - which I’m already not too happy about, especially as a given key can only be parent or child, not both but I couldn’t see a way to mix objects of a parent and child class together in the same dictionary.

What I want to happen to these dictionaries is identical. I want to loop through all the values and call the SpawnObject() . Both parent and child have the SpawnObject method but the child class does some extra checks before just calling the parent SpawnObject.

The dictionaries represent tiles, the key is always the grid position of the tile and then the value is either the parent class (SpawnableTile) or the more specific child class, which, amongst other things, restricts whether or not an object can spawn in that location.

I can’t see a way around writing out the processing code twice. I come from a php background so they’d all be in the same array to begin with there, but even if, for some reason they weren’t I could pass either array into a function and it would do the job. In c#, I can’t find a way to write a function that will accept an input that can be either a dictionary of ParentClass or ChildClass

Inheritance offers up what is called “polymorphism”. Polymorphism is where you can treat an object as its direct type, or any other type it inherits/implements (inherit from class, implement interface).

So if you have:

public class ClassA
{
    public virtual void Foo() { Console.WriteLine("A"); }
}

public class ClassB : ClassA
{
     public override void Foo() { Console.WriteLine("B"); }
}

You can treat an instance of ClassB as a ClassA. You can put instances of ClassB in a collection of ClassA. If you call Foo on an instance of ClassB, even though it’s typed as ClassA, it’ll call the override that’s in ClassB.

It’s the same as if you had a List and you stuck a bunch of your components in it. That List doesn’t change them into MonoBehaviour. They’re still their direct type. And if you access say the “enabled” property (which is defined in the ‘Behaviour’ class), it works.

So, just because you have a Dictionary<*, ParentClass>, you can still stick ChildClass into it, and call SpawnObject on them.

There are exceptions to this… if your ChildClass doesn’t ‘override’ a ‘virtual’ method. And instead uses the ‘new’ keyword:

The compiler only knows to call the ‘new’ version of the method in the ChildClass if the object is cast as that child type.

Generally you should avoid the ‘new’ modifier in this situation.

With all that said, you seem to not like your design with the Dictionary.

What is it you’re actually attempting to do? Not how you’re doing it… but your end goal. What is your design attempting to represent?

Maybe we can assist in giving you some direction.

1 Like

That’s how I thought it should work but when I tried it I got a lot of errors, maybe I had it the wrong way and put the child type in instead of the parent. Then I looked it up and someone on a forum was saying that even if I could do it, it would only call Parent::function and never Child::function if it was stored as Parent

Virtual and Override is exactly what I needed as the finishing touches. You are a legend and I am eternally grateful.

I’m now much happier with it all in the same dictionary but I shall describe what I’m trying to achieve incase there is a better way.

The overall goal is to be able to spawn objects on the map, in places I’ve specified. There is also an area of the map where the player can interact with the tiles and those interactions affect whether an object can spawn in that location. So I have the generic spawnable locations where the only requirement is that the square isn’t occupied. And then there is another area where items are allowed to spawn but only if the player hasn’t interacted with that tile.

How I’m doing it is I have an ObjectSpawner game object & script. I assign to that an array of prefab objects that can spawn and the tilemaps that represent the tiles they can spawn on.
The interactable tilemap has a script assigned that already looped through all its tiles and assigned them the Child type. The ObjectSpawner script loops through all the tilemaps assigned to it and if the tilemap is the interactible type it puts those tiles into its dictionary (with priority, if the dictionary already has a tile assigned, the child type replaces it - shouldn’t happen but just covering my bases). If its not an interactible type then it loops through the tiles and if there’s a tile it creates a spawnableobject tile and places it in the dictionary.
At a certain time, (once per “day”), the ObjectSpawner loops through the tiles it has and calls the SpawnObject() function