在我的表格上,我点击了一下按钮
private void button1_Click(object sender, EventArgs e)
{
do something
}
如何在点击时加载我从文本文件中执行的操作,例如我的文本文件如下所示:
MessageBox.Show("hello");
label1.Text = "Hello";
单击它会在我的文本文件中执行所有操作(如果可能)。
答案 0 :(得分:4)
这是一个非常简单的例子,只是为了证明这是可能的。基本上,您使用CodeDomProvider
在运行时编译源代码,然后使用反射执行。
var provider = CodeDomProvider.CreateProvider("C#");
string src=@"
namespace x
{
using System;
public class y
{
public void z()
{
Console.WriteLine(""hello world"");
}
}
}
";
var result = provider.CompileAssemblyFromSource(new CompilerParameters(), src);
if (result.Errors.Count == 0)
{
var type = result.CompiledAssembly.GetType("x.y");
var instance = Activator.CreateInstance(type);
type.GetMethod("z").Invoke(instance, null);
}
修改
正如@Agat指出的那样,OP似乎需要一种脚本框架(它使用label1
,这是当前对象的一个属性),而我上面的回答显然没有提供。我能想到的最好的是一个有限的解决方案,即要求将依赖关系明确指定为“脚本”中的参数。例如,编写如下脚本代码:
string src = @"
namespace x
{
using System.Windows;
public class y
{
public void z(Label label1)
{
MessageBox.Show(""hello"");
label1.Text = ""Hello"";
}
}
}
";
现在您可以让调用者检查参数,并使用反射再次从当前上下文传递它们:
var result = provider.CompileAssemblyFromSource(new CompilerParameters(), src);
if (result.Errors.Count == 0)
{
var type = result.CompiledAssembly.GetType("x.y");
var instance = Activator.CreateInstance(type);
var method = type.GetMethod("z");
var args = new List<object>();
// assume any parameters are properties/fields of the current object
foreach (var p in method.GetParameters())
{
var prop = this.GetType().GetProperty(p.Name);
var field = this.GetType().GetField(p.Name);
if (prop != null)
args.Add(prop.GetValue(this, null));
else if (field != null);
args.Add(field.GetValue(this));
else
throw new InvalidOperationException("Parameter " + p.Name + " is not found");
}
method.Invoke(instance, args.ToArray());
}
答案 1 :(得分:1)
与其他答案一样,实施起来并不容易,可以通过反思来完成,具体取决于脚本的高级程度。
但没有人 @BrankoDimitrijevic提到 Roslyn ,这是一个很棒的工具。 http://msdn.microsoft.com/en-us/vstudio/roslyn.aspx
它在相当长的一段时间内没有更新(2012年9月)并且没有实现C#的所有功能,但是,当我玩这个版本时它确实有很多实现。
通过添加程序集作为脚本会话的参考,您可以访问所有程序集的类型和脚本。它还支持返回值,因此您可以返回脚本方法生成的任何数据。
You can find what isn't implemented here.
以下是我刚刚编写和测试的一个快速而又脏的Roslyn示例。从NuGet安装Roslyn后,应该可以正常工作。脚本引擎初始化时的小膨胀可以很容易地包含在辅助类或方法中。
关键是传递HostObject
。它可以是任何东西。完成后,您的脚本将拥有对属性的完全访问权限。 请注意,您只需在脚本中调用属性而不是主机对象。
基本上,您的主机对象将包含脚本所需的数据属性。不必将主机对象视为单个数据对象,而是将其视为配置。
public class MyHostObject
{
public string Value1 { get; set; }
public string Value2 { get; set; }
}
public class RoslynTest
{
public void Test()
{
var myHostObject = new MyHostObject
{
Value1 = "Testing Value 1",
Value2 = "This is Value 2"
};
var engine = new ScriptEngine();
var session = engine.CreateSession(myHostObject);
session.AddReference(myHostObject.GetType().Assembly.Location);
session.AddReference("System");
session.AddReference("System.Core");
session.ImportNamespace("System");
// "Execute" our method so we can call it.
session.Execute("public string UpdateHostObject() { Value1 = \"V1\"; Value2 = \"V2\"; return Value1 + Value2;}");
var s = session.Execute<string>("UpdateHostObject()");
//s will return "V1V2" and your instance of myHostObject was also changed.
}
}
答案 2 :(得分:-1)
没有。你不能。
至少以任何简单的方式。
你想要的东西就像是来自javascript的eval('do something')
。
这与C#无法做到。 C#是一种在执行之前需要编译的语言,不像javascript(例如)。
实现它的唯一方法是构建自己的(非常复杂的初学者)解析器并以这种方式执行它。
<强>更新:强>
实际上,正如JDB公认的那样,这真的不是唯一的方法。我喜欢编程!有很多方法可以制作一个怪异的(有时甚至是某些自定义有趣的任务(甚至是学习)真正需要的!)代码。他他
我想到的另一种方法是构建一些.cs文件,然后即时编译它并将其作为一些程序集或其他模块使用。右。