Accessing object property as string and setting its value
C#StringEvalAccessorDatabinderC# Problem Overview
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?
C# Solutions
Solution 1 - C#
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");
Solution 2 - C#
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);
}
}
Solution 3 - C#
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.
Solution 4 - C#
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.
Solution 5 - C#
If you are using .Net 4 you can use the dynamic keyword now.
dynamic foo = account;
foo.Reference = "124ds4EE2s";
Solution 6 - C#
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;
}
}
}
Solution 7 - C#
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);
}
}
Solution 8 - C#
You need to use Reflection:
PropertyInfo property = typeof(Account).GetProperty("Reference");
property.SetValue(myAccount, "...", null);
Note that this will be very slow.
Solution 9 - C#
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);
}
Solution 10 - C#
how to access the list in an object using reflection by string name
public List
Solution 11 - C#
Here is a simple example, I hope it helps
static void Main(string[] args)
{
Operators op = new Operators()
{
ID = 1,
Name = "Edward",
email = "[email protected]",
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();
}