6

我的 CTO(首席技术官)要求我想出一种方法,让他可以在基类中编写一个函数,并可以访问子类的所有属性。这是我想出的-

基类

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;
    }
}

儿童班

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

程序.cs 文件

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

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

现在这工作正常,但我只是想知道在 C# 中是否有更好的方法来做到这一点。

请注意,我们不知道 子类中将存在哪些属性,因此必须在运行时确定。

更新说清楚,我只是想知道是否有更好的方法来访问子类属性,一种不使用反射的方法。需要注意的重要一点是,我们不知道子类可能具有哪些属性。

更新#2 :我正在使用具有许多实体的产品。这些实体具有不同的属性。我希望能够在一个地方访问和使用所有这些属性。这个功能正是如此。这是我可以访问所有数据的一个地方。

4

2 回答 2

6

首先,您的 Program.cs 实际上并没有“做”您所说的您想要的。听起来您想要一个程序,以便您可以这样做:

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

但是,你为什么还要这样做呢?如果你的资产不是房子,它会抛出一个异常,所以你需要先检查一下:

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

那时,您不妨将其投射到 House 中。听起来您可能想要使用 PropertyBag 或 Dictionary 而不是继承。

我想你所描述的就是这个。请注意,选项 1 并没有真正限制可以在哪些类上使用哪些属性,所以我猜这对于您的特定情况并不适用。

// 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;
        }
    }
}

然后,这就是您使用它们的方式:

// 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

第三种选择是使资产成为动态对象。 http://msdn.microsoft.com/en-us/library/system.dynamic.dynamicobject.aspx

如果您不能或不想对 Asset 基类进行重大更改或触摸每个实体,则可能需要使用反射。

于 2013-07-30T18:32:33.377 回答
1

卢克·格拉维特可能是对的。你可能只想把它扔到房子里。

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

Yacht myYacht = asObj as Yacht;
if ( myYacht != null )
{
   // put on monocle
}
于 2013-07-31T11:27:22.237 回答