문제

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.

도움이 되었습니까?

해결책

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.

다른 팁

Luke Gravitt is probably right. You might just want to cast it to a house.

House myHouse = asObj as House;
if ( myHouse != null )
{
  // do some fun house stuff
}

Yacht myYacht = asObj as Yacht;
if ( myYacht != null )
{
   // put on monocle
}
라이센스 : CC-BY-SA ~와 함께 속성
제휴하지 않습니다 StackOverflow
scroll top