简体   繁体   English

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

[英]Accessing object property as string and setting its value

I have an instance of the Account class.我有一个Account类的实例。 Each account object has an owner, reference, etc.每个帐户对象都有一个所有者、引用等。

One way I can access an accounts properties is through accessors like我可以访问帐户属性的一种方法是通过像这样的访问器

account.Reference;

but I would like to be able to access it using dynamic string selectors like:但我希望能够使用动态字符串选择器访问它,例如:

account["PropertyName"];

just like in JavaScript.就像在 JavaScript 中一样。 So I would have account["Reference"] which would return the value, but I also would like to be able to assign a new value after that like:所以我会有account["Reference"]它将返回值,但我也希望能够在之后分配一个新值,例如:

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

I've noticed I can use我注意到我可以使用

DataBinder.Eval(account,"Reference") 

to get a property based on a string, but using this I can't assign a value to the property.获取基于字符串的属性,但使用它我无法为该属性分配值。

Any idea on how I could do that?关于我如何做到这一点的任何想法?

First of all, you should avoid using this;首先,你应该避免使用它; C# is a strongly-typed language, so take advantage of the type safety and performance advantages that accompany that aspect. C# 是一种强类型语言,因此可以利用该方面带来的类型安全和性能优势。

If you have a legitimate reason to get and set the value of a property dynamically (in other words, when the type and/or property name is not able to be defined in the code), then you'll have to use reflection.如果您有正当理由动态获取和设置属性的值(换句话说,当无法在代码中定义类型和/或属性名称时),那么您将不得不使用反射。

The most inline-looking way would be this:最内联的方式是这样的:

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

However, you can cache the PropertyInfo object to make it more readable:但是,您可以缓存PropertyInfo对象以使其更具可读性:

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

object value = prop.GetValue(yourInstance);
...
prop.SetValue(yourInstance, "value");

You could try combining the indexer with reflection...您可以尝试将索引器与反射相结合...

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

If they are your own objects you could provide an indexer to access the fields.如果它们是您自己的对象,您可以提供一个索引器来访问这些字段。 I don't really recommend this but it would allow what you want.我真的不推荐这个,但它会允许你想要什么。

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

Note that you lose type safety when doing this.请注意,这样做会失去类型安全性。

If you are using .Net 4 you can use the dynamic keyword now.如果您使用的是 .Net 4,您现在可以使用 dynamic 关键字。

dynamic foo = account;
foo.Reference = "124ds4EE2s";

I used the reflection method from Richard, but elaborated the set method to handle other types being used such as strings and nulls.我使用了 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);
        }
    }
}

The SetValue() function will throw an error if the conversion doesn't work.如果转换不起作用,SetValue() 函数将抛出错误。

I agree with the previous posters that you probably do need to be using the properties.我同意之前的海报,您可能确实需要使用这些属性。 Reflection is very slow compared to direct property access.与直接访问属性相比,反射非常慢。

On the other hand, if you need to maintain a list of user-defined properties, then you can't use C# properties.另一方面,如果您需要维护用户定义的属性列表,则不能使用 C# 属性。 You need to pretend you are a Dictionary , or you need to expose a property that behaves like a Dictionary .您需要假装自己是一个Dictionary ,或者您需要公开一个行为类似于Dictionary的属性。 Here is an example of how you could make the Account class support user-defined properties:以下是如何使 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;
        }
    }
}

I personally prefer to work with extension methods so here is my code :我个人更喜欢使用扩展方法,所以这是我的代码:

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

You need to use Reflection:您需要使用反射:

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

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

Note that this will be very slow.请注意,这将非常缓慢。

Use reflection and expression bodies使用反射体和表达式体

        public dynamic this[string memberName]
        {
            get => GetType().GetProperty(memberName).GetValue(this, null);
            set => GetType().GetProperty(memberName).SetValue(this,value, null);
        }

how to access the list in an object using reflection by string name如何通过字符串名称使用反射访问对象中的列表
public List Table1 { get;公共列表表 1 { 获取; set;放; } = new List(); } = 新列表();

Here is a simple example, I hope it helps这是一个简单的例子,希望对你有帮助

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

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM