Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

C# get and set property by variable name

Is there any way to do this? I try to test if a property of an object exists and if it does, I want to set a value to it. (Maybe the complete idea is bad, if true - why?)

class Info
{
    public string X1{ set; get; }
    public string X2{ set; get; }
    public string X3{ set; get; }
}

Dictionary<string, string> values = new Dictionary<string, string>();
values.Add("X1","blah1");
values.Add("X2","blah2");
values.Add("NotThere","blah3");

Info info = new Info();

foreach (var item in values)
{
  string propertyName = item.Key;
  string value = item.Value;
  if (info.GetType().GetProperty(propertyName) != null)  //this probably works
  {
        info.propertyName = value; //this doesn't, how to set it?
  }
}
like image 318
Jan Matousek Avatar asked Aug 06 '12 07:08

Jan Matousek


4 Answers

Yes, your looking for the PropertyInfo.SetValue method e.g.

var propInfo = info.GetType().GetProperty(propertyName);
if (propInfo != null)
{
    propInfo.SetValue(info, value, null);
}
like image 185
James Avatar answered Oct 01 '22 23:10

James


var propertyInfo = info.GetType().GetProperty(propertyName);
if (propertyInfo != null)  //this probably works. Yes it is
  {
        propertyInfo.SetValue(info, value, null);
  }
like image 25
Amiram Korach Avatar answered Oct 02 '22 01:10

Amiram Korach


You need to invoke the SetValue method on the property:

var property = info.GetType().GetProperty(propertyName);
if (property != null)
{
    property.SetValue(info, value, null); 
}
like image 45
Matten Avatar answered Oct 02 '22 00:10

Matten


I think using reflection each time is a bit slow, so, if you do that initialization more than once you can use Expression Tree. But each time your dictionary should have same order of properties to init.

Possible code

class Info
{
    public string X1 { set; get; }
    public string X2 { set; get; }
    public int X3 { set; get; }
    private Action<Info, List<object>> initAction;

    public void Init(Dictionary<string, object> initDict)
    {
        //on first usage we deal with reflection and build expression tree to init properties
        if (initAction==null)
        {
            ParameterExpression targetInstanceExpression = Expression.Parameter(this.GetType());
            ParameterExpression valuesExpression = Expression.Parameter(typeof(List<object>));
            ParameterExpression value = Expression.Variable(typeof(object));
            ParameterExpression enumerator = Expression.Variable(typeof(IEnumerator));

            var expList = new List<Expression>();
            expList.Add(Expression.Assign(enumerator, Expression.TypeAs(Expression.Call(valuesExpression, "GetEnumerator", null),typeof(IEnumerator))));
            foreach (var initRecord in initDict)
            {
                Expression moveNextExp = Expression.Call(enumerator, "MoveNext", null);
                expList.Add(moveNextExp);
                Type type = initRecord.Value.GetType();
                expList.Add(Expression.Assign(value, Expression.PropertyOrField(enumerator, "Current")));
                Expression assignExp = GetPropAssigner(initRecord.Key, type, targetInstanceExpression, value);
                expList.Add(assignExp);
            }
            Expression block = Expression.Block
            (
                 new[] { value, enumerator },
                 expList
            );
            //compile epression tree and get init action 
            initAction = Expression.Lambda<Action<Info, List<object>>>(block, targetInstanceExpression, valuesExpression).Compile();
        }
        initAction(this, initDict.Values.ToList());
    }
    //little method to create property assigner
    public static Expression GetPropAssigner(string propName, Type type,
         ParameterExpression targetInstanceExp, ParameterExpression valueExp)
    {
        MemberExpression fieldExp = Expression.PropertyOrField(targetInstanceExp, propName);
        BinaryExpression assignExp = Expression.Assign(fieldExp, type.IsValueType ? Expression.Unbox(valueExp, type) : Expression.TypeAs(valueExp, type));
        return assignExp;
    }
}

Usage:

var values = new Dictionary<string, object>();
            values.Add("X1", "blah1");
            values.Add("X2", "blah2");
            values.Add("X3", 8);


Info info = new Info();
info.Init(values);
like image 29
Konstantin Chernov Avatar answered Oct 02 '22 00:10

Konstantin Chernov