开发者

Accessing object property as string and setting its value

I have an instance of the Account class. 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. 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"] = "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.

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:

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.


I used the reflection method from Richard, but elaborated the set method to handle other types being used such as strings and nulls.

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.


If you are using .Net 4 you can use the dynamic keyword now.

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


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. You need to pretend you are a Dictionary, or you need to expose a property that behaves like a Dictionary. Here is an example of how you could make the Account class support user-defined properties:

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

上一篇:

下一篇:

精彩评论

暂无评论...
验证码 换一张
取 消

最新问答

问答排行榜