【问题标题】:Execute a c# statement stored in a string variable [duplicate]执行存储在字符串变量中的c#语句[重复]
【发布时间】:2013-10-05 21:53:40
【问题描述】:

我想执行一个存储在字符串变量中的 C# 语句。例如:

string statement1 = "button1.Visible = true";
string statement2 = "button1.Text = \"Number\"";

【问题讨论】:

  • 你是说字符串中包含贴出的代码?
  • 您是否支持这种格式的代码:<object>.<property>=<value>?
  • 我想将命令存储在一个字符串中并执行它们@dotNET
  • @dotNET 它可能看起来像重复,但这个问题可能会通过完全不同的解决方案来解决。
  • 请验证,因为这个问题 (object.property=value) 比允许任意代码要简单得多。

标签: c#


【解决方案1】:

查看您的 cmets 并且您有 80 个控件需要非常相似的操作,为此目的,动态编译可能是多余的。您可以使用父容器的Controls 集合以及按钮的Tag 属性来实现它。单个事件处理程序就足够了。

您可以使用OfTypeCast 等LINQ 成员来使您的代码更小。

编辑

查看您的最新评论后,您应该以编程方式创建按钮并将它们添加到您的 Form 或您拥有的任何容器中。然后,您可以保留一个Dictionary<string, Button>,它可以让您遍历集合,或者通过其名称访问单个按钮。比如:

//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);
}

稍后您可以像这样进行两次迭代:

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

以及像这样基于密钥的访问:

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

由于您正在创建数独,我可能认为您应该在设计时使用具有适当数量的行和列的TableLayoutPanel,然后将您的按钮添加到面板并在循环中设置它们的 Row/Column 属性。这将有助于更好地响应调整大小事件等。

【讨论】:

  • 请你用一个简短的例子来解释一下
  • 请提供一些实际任务的细节,我也许可以为你写一些示例代码。
  • 我认为@Lasse V. Karlsen 做了我想做的事
【解决方案2】:

从您的 cmets 看来,您只是想迭代 80 多个类似的按钮并以相同的方式配置它们。这可以通过比执行动态代码简单得多的方式来完成。

这里有几种方法。

使用标签属性

首先在设计器中为 80 个按钮中的每一个设置 Tag 属性。

然后执行这段代码:

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

使用名称来识别他们:

确保所有 80 个按钮的名称为“buttonX”,其中 X 是一个数字。

然后执行这段代码:

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

其实是“执行代码”

如果,如你在你的 cmets 中所说,你只需要解决这个问题:“执行”这种类型的代码:

object.member=value

object 指的是存储在字段或属性中的内容。 member 指的是该对象的公共成员(字段或属性),而value 总是可以轻松转换为成员类型,那么下面的代码将起作用。

请注意,它缺少错误检查,因此请确保在使用之前检查代码。

ALSO 我一点也不相信这是合适的解决方案,但是由于您决定询问您想到的解决方案而不是实际问题,因此很难想出一个更好的解决方案。

你可以在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; }
}

这将输出(两个button1.Dump(); 语句)前后的按钮配置,您会注意到属性和字段已设置。

您可以按如下方式执行:

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

this 必须引用您的表单对象(拥有按钮的对象)。

【讨论】:

  • 我很难想象一个游戏屏幕有 80 个(即八十个)按钮,每个按钮都显示“数字”,而且这些按钮也会同时出现...... :)
  • 是的,我也是,但我很难弄清楚它还有什么含义。
  • "Number" 只是一个例子,实际上它是一个包含 81 个按钮的数独游戏,顺便感谢@dotNET 和@Lasse 的帮助:)
  • 再说一次,我不会使用您要求的方法,我会适当地命名 81 个按钮,或者将它们存储在数组中以便于参考或诸如此类。
  • 啊,我明白了。是的,只有数独和扫雷类游戏才能负担得起这么多按钮。查看我的编辑。
【解决方案3】:

使用委托怎么样?

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

【讨论】:

    猜你喜欢
    • 2018-12-01
    • 2011-01-07
    • 2012-02-15
    • 2016-08-24
    • 1970-01-01
    • 1970-01-01
    • 2018-11-10
    • 2017-05-24
    • 2011-05-17
    相关资源
    最近更新 更多