Search code examples
c#.netinheritanceclass-designmultiple-inheritance

Accessing child class properties through function in parent class


My CTO (Chief Technical Officer) asked me to come up with a way where he could write one single function in the base class, and have access to the all the properties of the child class. Here is what I came up with -

Base Class

class Assets
{
    public Assets getPropertyVal(Assets asObj)
    {
        PropertyInfo[] propInfos = asObj.GetType().GetProperties();
        string strAttributeValue = "10";
        foreach (PropertyInfo propInfo in propInfos)
        {
            // Getting the value
            var propValue = propInfo.GetValue(asObj, null);

            // Setting the value
            propInfo.SetValue(asObj, Convert.ChangeType(strAttributeValue, propInfo.PropertyType), null);

        }
        return asObj;
    }
}

Child Class

class House : Assets
{
    public int rooms{get; set;}
}

Program.cs file

class Program
{
    static void Main(string[] args)
    {
        House hsObj = new House();
        hsObj.rooms = 5;

        Assets asObj = hsObj.getPropertyVal(hsObj);
        // Returns asObj as JSON
    }
}

Now this works fine, but I was just wondering if there was a better way to do this in C#.

Note that we do not know what properties will be present in the child class, so this will have to be determined at run-time.

UPDATE : Making it clear, I was just wondering if there is a better way to access the child class properties, one without using reflection. The important point to note is that we have no idea what properties a child class may have.

UPDATE #2 : I am working with a product that has many entities. These entities have different properties. I want to be able to access and work with all these properties in one single place. This function is exactly that. It's that one single place from where I can access all the data.


Solution

  • First, your Program.cs doesn't actually "do" what you say you want. It sounds like you want a program so that you can do this:

    Asset myAsset = new House();
    myAsset.Rooms = 5;
    

    But, why would you even want to do that anyway? If your asset isn't a House, it will throw an exception, so you will need to check that first:

    if (myAsset is House)
        myAsset.Rooms = 5;
    

    At that point, you might as well just cast it to a House though. It sounds like you may want to use a PropertyBag or Dictionary instead of inheritance.

    I think what you are describing is this. Note that option 1 doesn't really restrict which properties can be used on which classes, so I'm guessing this won't really work for your specific case.

    // Option 1, a Property Bag (Note: this replaces the properties on the classes)
    class Asset
    {
        Dictionary<string, object> myPropertyBag = new Dictionary<string, object>();
    
        public T GetProperty<T>(string property)
        {
            // This throws if the property doesn't exist
            return (T)myPropertyBag[property];
        }
    
        public void SetProperty<T>(string property, T value)
        {
            // This adds the property if it doesn't exist
            myPropertyBag[property] = (object)value;
        }
    }
    
    // Option 2, use a switch and override this function in derived classes
    class Asset
    {
        public int SomePropertyOnAsset { get; set; }
    
        public virtual T GetProperty<T>(string property)
        {
            switch (property)
            {
                case "SomePropertyOnAsset": return this.SomePropertyOnAsset;
    
                default: throw new ArgumentException("property");
            }
        }
    
        public virtual void SetProperty<T>(string property, T value)
        {
            switch (property)
            {
                case "SomePropertyOnAsset": this.SomePropertyOnAsset = (int)value;
    
                default: throw new ArgumentException("property");
            }
        }
    }
    
    class House : Asset
    {
        public int Rooms { get; set; }
    
        public virtual T GetProperty<T>(string property)
        {
            switch (property)
            {
                case "Rooms": return this.Rooms;
    
                default: return base.GetProperty<T>(property);
            }
        }
    
        public virtual void SetProperty<T>(string property, T value)
        {
            switch (property)
            {
                case "Rooms": this.Rooms = (int)value; 
                    break;
    
                default: base.SetProperty<T>(property, value);
                    break;
            }
        }
    }
    

    Then, this is how you use them:

    // Option 1
    Asset asset = new House();
    asset.SetProperty("Rooms", 5);
    var rooms = asset.GetProperty<int>("Rooms");
    
    // Option 2
    Asset asset = new House();
    asset.SetProperty("Rooms", 5);
    asset.SetProperty("SomePropertyOnAsset", 10);
    asset.SetProperty("SomethingElse", 15); // Throws ArgumentException
    

    A 3rd option is to make Asset a DynamicObject. http://msdn.microsoft.com/en-us/library/system.dynamic.dynamicobject.aspx

    If you can't or don't want to make a major change to your Asset base class or touch every entity, you will probably need to use reflection.