以字符串形式访问对象属性并设置其值

zan*_*ona 43 c# string eval accessor databinder

我有一个Account班级的实例.每个帐户对象都有一个所有者,参考等.

我可以访问帐户属性的一种方法是通过访问器

account.Reference;
Run Code Online (Sandbox Code Playgroud)

但我希望能够使用动态字符串选择器访问它,如:

account["PropertyName"];
Run Code Online (Sandbox Code Playgroud)

就像在JavaScript中一样.所以我会有account["Reference"]哪些会返回值,但我也希望能够在之后分配一个新值,如:

account["Reference"] = "124ds4EE2s";
Run Code Online (Sandbox Code Playgroud)

我注意到我可以使用

DataBinder.Eval(account,"Reference") 
Run Code Online (Sandbox Code Playgroud)

获取基于字符串的属性,但使用此属性我无法为属性赋值.

我怎么能这样做?

Ada*_*son 68

首先,你应该避免使用它; C#是一种强类型语言,因此请充分利用该方面的类型安全性和性能优势.

如果你有合理的理由动态获取和设置属性的值(换句话说,当代码中无法定义类型和/或属性名称时),那么你将不得不使用反射.

最直观的方式是:

object value = typeof(YourType).GetProperty("PropertyName").GetValue(yourInstance);
...
typeof(YourType).GetProperty("PropertyName").SetValue(yourInstance, "value");
Run Code Online (Sandbox Code Playgroud)

但是,您可以缓存PropertyInfo对象以使其更具可读性:

System.Reflection.PropertyInfo prop = typeof(YourType).GetProperty("PropertyName");

object value = prop.GetValue(yourInstance);
...
prop.SetValue(yourInstance, "value");
Run Code Online (Sandbox Code Playgroud)

  • 有人告诉我C#太强烈了.经过一番反思后,我觉得这并不是那么糟糕. (94认同)
  • 你可以使用它来保存大量的编码(以及更少的代码=更少的错误).像ruby一样使用它,让你的db表与你的属性相匹配,专注于算法,而不是无限的输入(强大和键盘) (3认同)

Ric*_*end 32

您可以尝试将索引器与反射结合起来......

public object this[string propertyName]
{
    get
    {
        PropertyInfo property = GetType().GetProperty(propertyName);
        return property.GetValue(this, null);
    }
    set
    {
        PropertyInfo property = GetType().GetProperty(propertyName);
        property.SetValue(this,value, null);
    }
}
Run Code Online (Sandbox Code Playgroud)

  • +1也适合我.请注意,您需要处理可能为null的属性. (3认同)

Ste*_*han 6

如果它们是您自己的对象,您可以提供索引器来访问字段.我不是真的推荐这个,但它会允许你想要的东西.

public object this[string propertyName]
{
    get
    {
        if(propertyName == "Reference")
            return this.Reference;
        else
            return null;
    }
    set
    {
        if(propertyName == "Reference")
            this.Reference = value;
        else
            // do error case here            
    }
}
Run Code Online (Sandbox Code Playgroud)

请注意,执行此操作时会丢失类型安全性.


Rob*_*ick 6

如果您使用的是.Net 4,则可以立即使用dynamic关键字。

dynamic foo = account;
foo.Reference = "124ds4EE2s";
Run Code Online (Sandbox Code Playgroud)


Ken*_* Mc 6

我使用了Richard的反射方法,但是详细说明了set方法来处理正在使用的其他类型,例如字符串和空值.

public object this[string propertyName]
{
    get
    {
        PropertyInfo property = GetType().GetProperty(propertyName);
        return property.GetValue(this, null);
    }
    set
    {
        PropertyInfo property = GetType().GetProperty(propertyName);
        Type propType = property.PropertyType;
        if (value == null)
        {
            if (propType.IsValueType && Nullable.GetUnderlyingType(propType) == null)
            {
                throw new InvalidCastException();
            }
            else
            {
                property.SetValue(this, null, null);
            }
        }
        else if (value.GetType() == propType)
        {
            property.SetValue(this, value, null);
        }
        else
        {
            TypeConverter typeConverter = TypeDescriptor.GetConverter(propType);
            object propValue = typeConverter.ConvertFromString(value.ToString());
            property.SetValue(this, propValue, null);
        }
    }
}
Run Code Online (Sandbox Code Playgroud)

如果转换不起作用,SetValue()函数将抛出错误.