65

我有一个Account类的实例。每个帐户对象都有一个所有者、引用等。

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

account.Reference;

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

account["PropertyName"];

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

account["Reference"] = "124ds4EE2s";

我注意到我可以使用

DataBinder.Eval(account,"Reference") 

获取基于字符串的属性,但使用它我无法为属性分配值。

知道我该怎么做吗?

4

11 回答 11

94

首先,你应该避免使用这个;C# 是一种强类型语言,因此请利用伴随该方面的类型安全和性能优势。

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

最内联的方式是这样的:

object value = typeof(YourType).GetProperty("PropertyName").GetValue(yourInstance);
...
typeof(YourType).GetProperty("PropertyName").SetValue(yourInstance, "value");

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

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

object value = prop.GetValue(yourInstance);
...
prop.SetValue(yourInstance, "value");
于 2010-05-25T13:47:36.860 回答
41

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

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);
    }
}
于 2010-05-25T15:20:12.970 回答
7

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

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

请注意,这样做会失去类型安全性。

于 2010-05-25T13:56:41.027 回答
7

我使用了 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);
        }
    }
}

如果转换不起作用,SetValue() 函数将引发错误。

于 2017-01-12T05:36:20.293 回答
6

如果您使用的是 .Net 4,您现在可以使用 dynamic 关键字。

dynamic foo = account;
foo.Reference = "124ds4EE2s";
于 2015-09-04T10:29:11.650 回答
3

我同意之前的海报,您可能确实需要使用这些属性。与直接属性访问相比,反射非常慢。

另一方面,如果您需要维护用户定义属性的列表,则不能使用 C# 属性。您需要假装自己是 a Dictionary,或者您需要公开行为类似于 a 的属性Dictionary。下面是一个示例,说明如何使 Account 类支持用户定义的属性:

public class Account
{
    Dictionary<string, object> properties;
    public object this[string propertyName]
    {
        get
        {
            if (properties.ContainsKey[propertyName])
                return properties[propertyName];
            else
                return null;
        }
        set
        {
            properties[propertyName] = value;
        }
    }
}
于 2010-05-25T14:03:26.470 回答
2

我个人更喜欢使用扩展方法,所以这是我的代码:

public static class ReflectionExtensions
{
    public static void SetPropertyValue(this object Target,
        string PropertyName,
        object NewValue)
    {
        if (Target == null) return; //or throw exception

        System.Reflection.PropertyInfo prop = Target.GetType().GetProperty(PropertyName);

        if (prop == null) return; //or throw exception

        object value = prop.GetValue(Target, null);

        prop.SetValue(Target, NewValue, null);
    }
}
于 2014-10-03T13:40:50.720 回答
1

您需要使用反射:

PropertyInfo property = typeof(Account).GetProperty("Reference");

property.SetValue(myAccount, "...", null);

请注意,这将非常缓慢。

于 2010-05-25T13:48:37.347 回答
1

使用反射体和表达式体

        public dynamic this[string memberName]
        {
            get => GetType().GetProperty(memberName).GetValue(this, null);
            set => GetType().GetProperty(memberName).SetValue(this,value, null);
        }
于 2021-04-20T23:50:40.223 回答
0

如何通过字符串名称使用反射访问对象中的列表
public List Table1 { get; 放; } = 新列表();

于 2021-11-25T11:49:30.877 回答
-1

这是一个简单的例子,希望对你有帮助

static void Main(string[] args)
{
    Operators op = new Operators()
    {
        ID = 1,
        Name = "Edward",
        email = "e.lorenz@mail.com",
        Pass = "123456",
        Auth1 = "EDF3242523@FFSDGDF"
    };

    var typei = op.GetType();
    var ss = typei.GetProperties().Where(m => m.GetCustomAttributes<Password>().Count() > 0);

    foreach (var item in ss)
    {
        var text = typei.GetProperty(item.Name).GetValue(op).ToString();
        
        typei.GetProperty(item.Name).SetValue(op, Encrypt(text));
    }

    Console.WriteLine(op.Pass);
    Console.WriteLine(op.Auth1);

    Console.ReadKey();
}
于 2021-06-03T13:19:16.307 回答