C# : Override property type in a derived class

Hello everybody, during the development of our multiplayer game, we have been facing of a big problem : How can we easely override a property type in a derived class ?

I browsed the web a long time whitout finding a good solution. The best one i tried was to use generic type. It’s ok only if you have one property to override, but if you have more than one, it will become fastly hard to maintain and you code will be much complicated.

So, i found my own solution. We’ll use the “new” keyword and polymorphism !

The context

In our game, we have a class base (Building) for our building, and derived class for each building type (BuildingProducer and BuildingPassive). Each building can be upgraded. The level contains specific information depending the type of the building.

We have in our Building class a property Level wich is an instance of the BuildingLevel class. But for each derived class, we need to override the level property type with the specific level class :

The solution

To handle this very particular situation, the solution is to use a combination of the “new” keyword and polymorphism.

The new keyword will hide the property with the same name on the base class.

The base class : Building

public class Building
    {
        #region Properties

        public int Id { get; set; }
        public string Name { get; set; }

        private Level level;
        public Level Level {
            get { return GetLevel(); } //To use polymorphism
            set { SetLevel(value); } //To use polymorphism
        }

        #endregion

        #region Level virtual

        /// <summary>
        /// Useful to use metamorphism and thus, get the child model when call Building properties
        /// </summary>
        /// <returns></returns>
        protected virtual Level GetLevel()
        {
            return level;
        }

        /// <summary>
        /// Useful to use metamorphism and thus, get the child model when call Building properties
        /// </summary>
        /// <returns></returns>
        protected virtual void SetLevel(Level pLevel)
        {
            level = pLevel;
        }

        #endregion
    }

You can see that we are using virtual methods. By doing that, when we call the GetLevel() and SetLevel(), the engine will automatically determine the real type of the objet and call the method in the real class.

Now, we just need to define these methods in the derived classes.

Derived classes : BuildingProducer and BuildingPassive

I only will paste the code of the Producer building because, the code is the same for both classes :

    public class BuildingProducer : Building
    {

        #region Properties

        /// <summary>
        /// Hide the base property, but they both exists
        /// </summary>
        public new LevelProducer Level {
            get { return GetLevel() as LevelProducer; }
            set { SetLevel(value); }
        }
        private LevelProducer level;

        #endregion

        /// <summary>
        /// Useful to use metamorphism and thus, get the child model when call Building properties
        /// </summary>
        /// <returns></returns>
        protected override Level GetLevel()
        {
            return Level;
        }

        /// <summary>
        /// Useful to use metamorphism and thus, get the child model when call Building properties
        /// </summary>
        /// <returns></returns>
        protected override void SetLevel(Level pLevel)
        {
            level = pLevel as LevelProducer;
        }

    }

Usage exemple

You can now use this common property Level defined in the base class with dynamic type returned thanks to polymorphism.

            List<Building> buildings = new List<Building>();

            //Create a new building
            BuildingProducer derivedBuildingProducer = new BuildingProducer
            {
                Id = 1,
                Name = "Test",
                Level = new LevelProducer { Id = 1, Cost = 200, ResourceProducedId = 1, Amout = 20 }
            };
            buildings.Add(derivedBuildingProducer);
            

            //Create a new building
            BuildingPassive derivedBuildingPassive = new BuildingPassive
            {
                Id = 1,
                Name = "Test",
                Level = new LevelPassive { Id = 1, Cost = 200, PassiveIncome = 1 }
            };
            buildings.Add(derivedBuildingPassive);

            //Polymorphism allow to return different type with the same variable name
            Console.Write(buildings[0].Level.GetType().ToString()); //Will return a LevelProducer
            Console.Write(buildings[1].Level.GetType().ToString()); //Will return a LevelPassive
Posted in Best Practice.

Leave a Reply

Your email address will not be published. Required fields are marked *