views:

397

answers:

6

Is it possible to get the property of a class from string and then set a value?

Example:

string s = "label1.text";
string value = "new value";

label1.text = value; <--and some code that makes this

How to do this?

+4  A: 

You can use reflection to do this, but it will be quite slow?

Perhaps if you tell us what you're trying to achieve by doing this we can help, there are several patterns on event handlers etc. that usually makes this unnecessary.

Spence
I wouldn't say it's really slow. I mean many, many frameworks are based around using Reflection extensively; much of databinding stuff utilizes reflection on properties.
BobbyShaftoe
There are many ways to optimize - so I wouldn't write off reflection because of performance concerns, especially without profiling.
Nader Shirazie
I'm making a translator. I have a text file where are keys like "label1.text" and values like "new value" -> label1.text=new value. so there are many keys and values.
Jooj
Reflection will be significantly slower than using a delegate or object reference. If you are in control of the API you are coding against then you shouldn't need to use reflection. From what I've seen here @Jooj might be better off pulling up a copy of IronPython and doing some gui coding with it...
Spence
@ Spence - You can always optimize your reflection use when needed. For example, you can cache method calls through reflection by creating a delegate with `Delegate.CreateDelegate` and invoking that delegate.
JulianR
+1  A: 

You need an instance of the object whose properties you want to set. From your example I'll pretend it is a label.

Label myLabel = new Label();
string s = "text";
string value = "new value";
System.Reflection.PropertyInfo[] properties = myLabel.GetType().GetProperties();
foreach (System.Reflection.PropertyInfo p in properties) 
{
    if(p.Name == s)
    {
         p.SetValue(myLabel, value, null);
    }
}
Ragepotato
Ok, but how to do it, when I have more labels and I want to set the value to custom string not only to one label. Example: "label1.text" or "Form.Text" or "MyClass.Text". How to get the class name instance?
Jooj
If you have more labels you could extract the code into a method and call it repeatedly. The "custom string" could be a param to the method. I'm not quite sure that is the answer to your question though. Could you elaborate?
Ragepotato
+4  A: 

Based this source, the equivalent of

shipment.<propName> = valueToUse,

where 'propName' is the name of the property provided as a string:

using System;
using System.Reflection;

namespace PropertyViaString
{
    public class Shipment
    {
        public string Sender { get; set; }
    }
    class Program
    {
        static void Main(string[] args)
        {
            Shipment shipment = new Shipment();
            SetValueExample(shipment, "Sender", "Popeye");
            Console.WriteLine("Sender is {0}", shipment.Sender);
            Console.ReadKey();
        }

        static void  SetValueExample(Shipment shipment, string propName, string valueToUse)
        {
            Type type = shipment.GetType();
            PropertyInfo senderProperty = type.GetProperty(propName);
            senderProperty.SetValue(shipment, valueToUse, null);
        }

    }
}

prints

Sender is Popeye
Phillip Ngan
+2  A: 

The answer is use Reflection. However, there are many app frameworks that make the process much easier.

For example, have a look at Spring.Net Expressions. It allows you to do:

ExpressionEvaluator.SetValue(object, "label1", "text");

It is much more powerful and flexible than this simple example, so have a look.

Nader Shirazie
Woohoo, how could that one slip under my radar? Thx fro bringing it up. Anyway, seems exactly like what the OP wanted to have.
Robert Giesecke
A: 

I found this code:

Object someObject = myForm; <--- want to make this Object someObject = "myForm";
String propName = "Title";
System.Reflection.PropertyInfo pi = someObject.GetType().GetProperty(propName);
pi.SetValue(someObject, "New Value", new Object[0]);

It works. But what to do, that it would by possible to set someObject as a string.

Object someObject = (object)"myForm" <-- this doesn't work.
Jooj
+1  A: 

If the given control is an instance variable on your form (if you used the built-in WinForms designer, most are), first get the control, and then set the property on it:

    void Form_SetControlProperty(
        String controlName, String propertyName, object value)
    {
        FieldInfo controlField = this.GetType().GetField(controlName, 
            BindingFlags.Instance | BindingFlags.NonPublic | BindingFlags.Public);
        object control = controlField.GetValue(this);
        PropertyInfo property = control.GetType().GetProperty(propertyName);
        property.SetValue(control, value, new object[0]);
    }

You may need to tweak BindingFlags to get this to work.

This must be a method on your form. Call it as: SetControlProperty("myLabel", "Text", "my label text");

Pay attention to the scope of the method. It any control within the form, but not the form itself (to access the form itself, set control to this).

Note that this uses reflection and will be slow and brittle (change the name of a control and it will break).

dbkk
Wow, thanks. Is there a faster way?
Jooj
If you do run into performance problems, it might be worth caching the PropertyInfo (say, in a Dictionary indexed by controlName.propertyName). Not sure how much it would help, depends on your usage pattern.
dbkk