-4

I want to execute a C# statement which is stored in a string variable. For instance:

string statement1 = "button1.Visible = true";
string statement2 = "button1.Text = \"Number\"";
12
  • Are you saying that the string contains the posted code? Commented Sep 30, 2013 at 6:03
  • 1
    Are you only going to support code on this format: <object>.<property>=<value>? Commented Sep 30, 2013 at 6:05
  • i want to store the commands in a string and execute them @dotNET Commented Sep 30, 2013 at 6:06
  • 1
    @dotNET It may look like a duplicate but this problem might be solved by a completely different solution. Commented Sep 30, 2013 at 6:06
  • 2
    Please verify, because that problem (object.property=value) is much much simpler than allowing for arbitrary code. Commented Sep 30, 2013 at 6:07

3 Answers 3

2

Looking at your comments and that you have 80 controls requiring very similar action, dynamic compilation may be an overkill for this purpose. You can use use Controls collection of the parent container along with the Tag property of your buttons to achieve it. A single event handler would suffice.

You can use LINQ members like OfType and Cast to make your code even smaller.

Edit

After looking at your latest comment, what you should do is to programmatically create your buttons and add them to your Form or whatever container you have. You can then keep a Dictionary<string, Button> that will let you either iterate over the collection, or access an individual button through its name. Something like:

//Declare this globally
Dictionary<string, Button> Dic = new Dictionary<string, Button>(81);

//put this in the constructor
for(int i=0; i<81; i++)
{
    Button b = new Button();
    b.Text = i; //or Random or whatever
    b.Name = "btn" + i.ToString();
    this.Controls.Add(b);
    Dic.Add(b.Name, b);
}

Later you can do both iteration like this:

foreach(var item in Dic)
{
    item.Value.Visible = true; //or false
}

and key-based access like this:

Dic["btn45"].Visible = true; //or false

Since you're creating Sudoku, i probably think you should use TableLayoutPanel with appropriate number of rows and columns at design-time and then add your buttons to the panel and set their Row/Column property in the loop. This will help better respond to resizing events etc.

Sign up to request clarification or add additional context in comments.

3 Comments

will you explain with a short example please
Plz provide some detail of the actual task and I may be able to write some sample code for you.
i think @Lasse V. Karlsen has done something i want to do
1

From your comments it appears you simply want to iterate over 80 similar buttons and configure them the same way. This can be accomplished by far simpler means than executing dynamic code.

Here's a couple of ways.

Use the tag property

First set the Tag property to a specific number in the designer for each of the 80 buttons.

Then execute this code:

foreach (var button in Controls.OfType<Button>().Where(button => button.Tag == "TAG"))
{
    button.Visible = true;
    button.Text = "Number";
}

Use the name to identify them:

Ensure all the 80 buttons have a name of "buttonX" where X is a number.

Then execute this code:

foreach (var button in Controls.OfType<Button>().Where(button => button.Name.StartsWith("button"))
{
    button.Visible = true;
    button.Text = "Number";
}

Actually "execute code"

If, as you say in your comments, you only need to solve this problem: "Execute" this type of code:

object.member=value

Where object refers to something stored in a field or property. member refers to a public member (field or property) of that object, and value is something that will always be easily convertible to the member type, then the following code will work.

Note that it is short on error checking, so please make sure you vet the code before using it.

ALSO I am not convinced in the very slightest that this is the appropriate solution, but since you've decided to ask about the solution you had in mind instead of the actual problem, it's hard to come up with a better solution.

You can run this code in LINQPad:

void Main()
{
    button1.Dump();
    SetProperties(this,
        "button1.Visible=true",
        "button1.Text=\"Number\""
    );
    button1.Dump();
}

public static void SetProperties(object instance, params string[] propertySpecifications)
{
    SetProperties(instance, (IEnumerable<string>)propertySpecifications);
}

public static void SetProperties(object instance, IEnumerable<string> propertySpecifications)
{
    var re = new Regex(@"^(?<object>[a-z_][a-z0-9_]*)\.(?<member>[a-z_][a-z0-9_]*)=(?<value>.*)$", RegexOptions.IgnoreCase);
    foreach (var propertySpecification in propertySpecifications)
    {
        var ma = re.Match(propertySpecification);
        if (!ma.Success)
            throw new InvalidOperationException("Invalid property specification: " + propertySpecification);

        string objectName = ma.Groups["object"].Value;
        string memberName = ma.Groups["member"].Value;
        string valueString = ma.Groups["value"].Value;
        object value;
        if (valueString.StartsWith("\"") && valueString.EndsWith("\""))
            value = valueString.Substring(1, valueString.Length - 2);
        else
            value = valueString;

        var obj = GetObject(instance, objectName);
        if (obj == null)
            throw new InvalidOperationException("No object with the name " + objectName);

        var fi = obj.GetType().GetField(memberName);
        if (fi != null)
            fi.SetValue(obj, Convert.ChangeType(value, fi.FieldType));
        else
        {
            var pi = obj.GetType().GetProperty(memberName);
            if (pi != null && pi.GetIndexParameters().Length == 0)
                pi.SetValue(obj, Convert.ChangeType(value, pi.PropertyType));
            else
                throw new InvalidOperationException("No member with the name " + memberName + " on the " + objectName + " object");
        }
    }
}

private static object GetObject(object instance, string memberName)
{
    var type = instance.GetType();
    var fi = type.GetField(memberName, BindingFlags.NonPublic | BindingFlags.Instance | BindingFlags.Default);
    if (fi != null)
        return fi.GetValue(instance);

    var pi = type.GetProperty(memberName, BindingFlags.NonPublic | BindingFlags.Instance | BindingFlags.Default);
    if (pi != null && pi.GetIndexParameters().Length == 0)
        return pi.GetValue(instance, null);

    return null;
}

private Button button1 = new Button();

public class Button
{
    public bool Visible;
    public string Text { get; set; }
}

This will output (the two button1.Dump(); statements) the button configuration before and after, and you'll notice that the property and the field have been set.

You can execute this as follows:

`SetProperties(this, "...", "...");

where this must refer to your form object (the one that owns the buttons).

5 Comments

I have a hard time imagining a game screen with 80 (EIGHTY that is) buttons each saying "Number", and those too appearing at once... :)
Yes, me too, but I have a hard time figuring out what else it could mean.
"Number" was just an example actually its a sudoku game containing 81 buttons, btw thanks for help @dotNET and @ Lasse :)
Then again, I would not use the approach you've asked for, I would either name the 81 buttons appropriately, or store them in arrays for easy reference or whatnot.
Ah i see. Yes only sudoku and minesweeper kind of games can afford that number of buttons. See my edit.
1

What about using delegates?

Action statement1 = () => button1.Visible = true;
Action statement2 = () => button1.Text = "Number";

Comments

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.