有没有一种方法可以将键/值语法添加到C#中的对象?

时间:2018-08-30 13:09:16

标签: c# extension-methods

我有一个名为CottonCandy的对象。 CottonCandy具有一些特性:

  • 质量
  • 音量
  • 总糖
  • 颜色

很棒的是,如果我可以向CottonCandy添加一些东西,以便可以像这样检索属性:

var colors = cottonCandy["Colors"];

通过阅读this,您似乎可以通过以下方式获得价值:

cottonCandy.GetType().GetProperty("Colors").GetValue(cottonCandy, null);

,您可以轻松地将其包装在方法中:

var colors = cottonCandy.GetPropertyValue("Colors");

但是我真的更喜欢键/值语法cottonCandy["Colors"]。有什么办法可以做到这一点?

5 个答案:

答案 0 :(得分:6)

实际上有一种方法。您可以使用indexers。但是,您需要具有相同的字段类型或在object类型中输入值。

class CottonCandy
{
    private int Mass { get; set; }
    private int Volume { get; set; }
    private int TotalSugar { get; set; }
    private int Colors { get; set; }

    public int this[string field]
    {
        get
        {
            PropertyInfo propertyInfo = typeof(CottonCandy).GetProperty(field);
            if(propertyInfo == null)
                throw new ArgumentException("Invalid field");
            return (int)propertyInfo.GetValue(this);
        }
    }
}

答案 1 :(得分:2)

您可以做到

public class CottonCandy
    {

        public string Mass { get; set; }
        public string Volume { get; set; }
        public string TotalSugar { get; set; }
        public string Colors { get; set; }
        public string this[string key]
        {
            get
            {
                switch (key)
                {
                    case "Mass":
                        return this.Mass;
                    case "Volume":
                        return this.Volume;
                    case "TotalSugar":
                        return this.TotalSugar;
                    case "Colors":
                        return this.Colors;
                    default:
                        return "";
                }

            }
            set
            {
                switch (key)
                {
                    case "Mass":
                        this.Mass = value; break;
                    case "Volume":
                        this.Volume = value; break;
                    case "TotalSugar":
                        this.TotalSugar = value; break;
                    case "Colors":
                        this.Colors = value; break;
                    default:
                        break;
                }
            }
        }


    }

答案 2 :(得分:1)

这不是键/值语法。但是,如果决定使用扩展名,则可以使用此扩展名方法。此Nuget软件包中有类似的扩展名

public static T GetFieldValue<T>(this object obj, string fieldName)
{
    T result;
    PropertyInfo propertyInfo = obj.GetType().GetProperty(fieldName);
    if (propertyInfo != null)
    {
        result = (T)propertyInfo.GetValue(obj);
    }
    else
    {
        throw new FieldAccessException($"{fieldName} cannot be found");
    }
    return result;
}

您可以通过this link访问更多扩展程序。也许unit tests提供了有关方法用法和结果的线索。

更新:

您可以像下面这样结合扩展方法和索引器:

public class TestClass
{
    public string this[string field]
    {
        get => this.GetFieldValue<string>(field);
        set => this.TrySetFieldValue(field, value);
    }
}

答案 3 :(得分:1)

尝试查看对象索引器:https://docs.microsoft.com/en-us/dotnet/csharp/programming-guide/indexers/

一种方法是使用索引器,并使用“ nameof”运算符将索引器字符串值与可用属性进行比较。这会使代码更加冗长,但避免了反思。

但是,请确保这确实是您真正想要的,因为如果您以这种方式访问​​属性,您将不再获得编译时检查的好处。

答案 4 :(得分:0)

如果您的类是一个简单的数据对象,没有任何行为,并且只有这样的简单属性,则可以将其设置为Dictionary

var map = new Dictionary<string, whatever> { { "Colors", ... }, { "Mass", ... } ... };
map["Colors"] = ...;

否则,您应该像已经提到的那样使用反射。