Search code examples
c#oopdowncast

How to setup C# downcasting in a more dynamic way


Apologies if the title is not quite right.
I've got a set of base classes I am deriving from. There is a main one and a bunch of components I can add onto it.

    public class Entity {
        public EntityPart ep;
    }
    public class EntityPart {
        public void eFunc() {}
    }

My derived classes work perfect for all my virtual functions obviously. But here's the problem I ran into

    public class dEntity : Entity {
        public void someFunc() {
            ep.derivedFunc(); // Error, does not exist on EntityPart
        }
    }
    public class dEntityPart : EntityPart {
        public void derivedFunc() {}
    }

I pretty quickly figured out what was going on. Since ep was still just an EntityPart it didn't have the derived functionality.

I found a solution that worked but felt like something was off. When I asked others they seemed confused that my code didn't work before.

    public class dEntity : Entity {
        public new dEntityPart ep {
            get { return (dEntityPart)base.ep; }
        }
    }

As I understand this is simply declaring a variable named ep as the type dEntityPart. This is a property and has the get function that casts base.ep (which is just EntityPart) as a dEntityPart. The new keyword hides base from within the class.
I'd like to double check first that this understanding is correct.

This worked just as I needed but it seemed messy. I have many sets of derivations of these class, each with many parts. This method feels a little slow and cumbersome. Is there a way to set up this down casting to always be there, or perhaps a way to setup some generic to work like this?

If this is the way to do it, alrighty. I'm interested in perhaps a more elegant method or some better way to set up such code. Thanks!


Solution

  • Does this work for you?

        public class Entity<T> where T : EntityPart {
            public T ep;
        }
        public class EntityPart {
            public void eFunc() {}
        }
    
        public class dEntity : Entity<dEntityPart> {
            public void someFunc() {
                ep.derivedFunc(); // This won't throw an error anymore.
            }
        }
        public class dEntityPart : EntityPart {
            public void derivedFunc() {}
        }