从C#脚本调用外部应用程序方法
在将脚本功能集成到我的团队构建的应用程序中方面,我已经取得了很多进展,但目前我有点陷入困境 我们有我们已经编写的数据采集软件(应用程序),我们也希望有脚本功能。我在应用程序中嵌入了一个类,可以读取和编译外部编写的脚本。例如,我可以编写一个没有以任何方式链接到应用程序的.cs文件,并在运行时调用该文件,成功地执行它 为了扩展脚本的实用性,我现在需要做的是从脚本中调用应用程序中预先存在的方法。我将尝试用以下示例来描述所有这些: 这里有我的脚本文件,在应用程序运行时,我可以随时更改它 ScriptFile.cs从C#脚本调用外部应用程序方法,c#,scripting,C#,Scripting,在将脚本功能集成到我的团队构建的应用程序中方面,我已经取得了很多进展,但目前我有点陷入困境 我们有我们已经编写的数据采集软件(应用程序),我们也希望有脚本功能。我在应用程序中嵌入了一个类,可以读取和编译外部编写的脚本。例如,我可以编写一个没有以任何方式链接到应用程序的.cs文件,并在运行时调用该文件,成功地执行它 为了扩展脚本的实用性,我现在需要做的是从脚本中调用应用程序中预先存在的方法。我将尝试用以下示例来描述所有这些: 这里有我的脚本文件,在应用程序运行时,我可以随时更改它 ScriptFi
namespace SimpleScripts
{
public class MyScriptMul5 : ScriptingInterface.IScriptType1
{
public string RunScript(int value)
{
System.Console.WriteLine("Hello World! This works!");
//NEED THIS: Code to call pre-existing method in application
}
}
}
namespace ScriptingInterface
{
public interface IScriptType1
{
string RunScript(int value);
}
}
namespace ScriptingExample
{
public static class ScriptingEx
{
public static void StartScript()
{
string path = @"TestScript1.cs";
// Open the file to read from.
string readText = File.ReadAllText(path);
Assembly compiledScript = CompileCode(readText);
if (compiledScript != null)
{
RunScript(compiledScript);
}
}
static Assembly CompileCode(string code)
{
Microsoft.CSharp.CSharpCodeProvider csProvider = new Microsoft.CSharp.CSharpCodeProvider();
CompilerParameters options = new CompilerParameters();
options.GenerateExecutable = false;
options.GenerateInMemory = true;
options.ReferencedAssemblies.Add(Assembly.GetExecutingAssembly().Location);
// Compile our code
CompilerResults result;
result = csProvider.CompileAssemblyFromSource(options, code);
if (result.Errors.HasErrors)
{
// Report back to the user that the script has errored
Console.WriteLine("Script has errored");
for (int i = 0; i < result.Errors.Count; i++)
{
Console.WriteLine("Error {0}: {1}", i+1, result.Errors[i]);
}
return null;
}
if (result.Errors.HasWarnings)
{
Console.WriteLine("Script has warnings");
}
return result.CompiledAssembly;
}
static void RunScript(Assembly script)
{
foreach (Type type in script.GetExportedTypes())
{
foreach (Type iface in type.GetInterfaces())
{
if (iface == typeof(ScriptingInterface.IScriptType1))
{
ConstructorInfo constructor = type.GetConstructor(System.Type.EmptyTypes);
if (constructor != null && constructor.IsPublic)
{
ScriptingInterface.IScriptType1 scriptObject = constructor.Invoke(null) as ScriptingInterface.IScriptType1;
if (scriptObject != null)
{
//Lets run our script and display its results
MessageBox.Show(scriptObject.RunScript(50));
}
}
}
}
}
}
public static void TestExternalCall1()
{
Console.WriteLine("Called successfully!");
}
}
}
namespace SimpleScripts
{
public class MyScriptMul5 : ScriptingInterface.IScriptType1
{
public string RunScript(ScriptingInterface.IServiceProvider serviceProvider, int value)
{
System.Console.WriteLine("Hello World! This works!");
serviceProvider.Messenger.SendMessage("Test");
}
}
}
很抱歉,有这么大的代码块,但我想我会包括所有内容,以防出现问题。我所要做的就是使用上面的脚本调用方法TestExternalCall,同时通过这个脚本处理程序运行它
ScriptHandler.cs
namespace SimpleScripts
{
public class MyScriptMul5 : ScriptingInterface.IScriptType1
{
public string RunScript(int value)
{
System.Console.WriteLine("Hello World! This works!");
//NEED THIS: Code to call pre-existing method in application
}
}
}
namespace ScriptingInterface
{
public interface IScriptType1
{
string RunScript(int value);
}
}
namespace ScriptingExample
{
public static class ScriptingEx
{
public static void StartScript()
{
string path = @"TestScript1.cs";
// Open the file to read from.
string readText = File.ReadAllText(path);
Assembly compiledScript = CompileCode(readText);
if (compiledScript != null)
{
RunScript(compiledScript);
}
}
static Assembly CompileCode(string code)
{
Microsoft.CSharp.CSharpCodeProvider csProvider = new Microsoft.CSharp.CSharpCodeProvider();
CompilerParameters options = new CompilerParameters();
options.GenerateExecutable = false;
options.GenerateInMemory = true;
options.ReferencedAssemblies.Add(Assembly.GetExecutingAssembly().Location);
// Compile our code
CompilerResults result;
result = csProvider.CompileAssemblyFromSource(options, code);
if (result.Errors.HasErrors)
{
// Report back to the user that the script has errored
Console.WriteLine("Script has errored");
for (int i = 0; i < result.Errors.Count; i++)
{
Console.WriteLine("Error {0}: {1}", i+1, result.Errors[i]);
}
return null;
}
if (result.Errors.HasWarnings)
{
Console.WriteLine("Script has warnings");
}
return result.CompiledAssembly;
}
static void RunScript(Assembly script)
{
foreach (Type type in script.GetExportedTypes())
{
foreach (Type iface in type.GetInterfaces())
{
if (iface == typeof(ScriptingInterface.IScriptType1))
{
ConstructorInfo constructor = type.GetConstructor(System.Type.EmptyTypes);
if (constructor != null && constructor.IsPublic)
{
ScriptingInterface.IScriptType1 scriptObject = constructor.Invoke(null) as ScriptingInterface.IScriptType1;
if (scriptObject != null)
{
//Lets run our script and display its results
MessageBox.Show(scriptObject.RunScript(50));
}
}
}
}
}
}
public static void TestExternalCall1()
{
Console.WriteLine("Called successfully!");
}
}
}
namespace SimpleScripts
{
public class MyScriptMul5 : ScriptingInterface.IScriptType1
{
public string RunScript(ScriptingInterface.IServiceProvider serviceProvider, int value)
{
System.Console.WriteLine("Hello World! This works!");
serviceProvider.Messenger.SendMessage("Test");
}
}
}
命名空间脚本接口
{
公共接口IScriptType1
{
字符串RunScript(int值);
}
}
命名空间脚本示例
{
公共静态类ScriptingEx
{
公共静态无效StartScript()
{
字符串路径=@“TestScript1.cs”;
//打开要从中读取的文件。
字符串readText=File.ReadAllText(路径);
汇编compiledScript=CompileCode(readText);
if(compiledScript!=null)
{
RunScript(compiledScript);
}
}
静态程序集编译代码(字符串代码)
{
Microsoft.CSharp.CSharpCodeProvider csProvider=新的Microsoft.CSharp.CSharpCodeProvider();
CompilerParameters选项=新的CompilerParameters();
options.GenerateExecutable=false;
options.GenerateInMemory=true;
options.referencedAssembly.Add(Assembly.getExecutionGassembly().Location);
//编译我们的代码
编译结果;
结果=csProvider.CompileAsemblyFromSource(选项、代码);
if(result.Errors.HasErrors)
{
//向用户报告脚本出错
Console.WriteLine(“脚本出错”);
对于(int i=0;i
如果您有任何问题,请告诉我,希望我已经说清楚了。在我的一个项目中,我实现了类似的功能。我们通过提供
RunScript
方法的接口来解决这个问题,该方法公开了runner的不同服务。
它允许脚本编写者在提交给executor之前模拟服务并测试它们的代码。
这种方法的另一个好处是,您将在编译过程中发现不兼容问题。
作为替代解决方案,您可以使用反射,但它不是强类型和
如果您的执行者的服务已更改,您可能会在运行时遇到问题
例如:
您的宏
namespace SimpleScripts
{
public class MyScriptMul5 : ScriptingInterface.IScriptType1
{
public string RunScript(int value)
{
System.Console.WriteLine("Hello World! This works!");
//NEED THIS: Code to call pre-existing method in application
}
}
}
namespace ScriptingInterface
{
public interface IScriptType1
{
string RunScript(int value);
}
}
namespace ScriptingExample
{
public static class ScriptingEx
{
public static void StartScript()
{
string path = @"TestScript1.cs";
// Open the file to read from.
string readText = File.ReadAllText(path);
Assembly compiledScript = CompileCode(readText);
if (compiledScript != null)
{
RunScript(compiledScript);
}
}
static Assembly CompileCode(string code)
{
Microsoft.CSharp.CSharpCodeProvider csProvider = new Microsoft.CSharp.CSharpCodeProvider();
CompilerParameters options = new CompilerParameters();
options.GenerateExecutable = false;
options.GenerateInMemory = true;
options.ReferencedAssemblies.Add(Assembly.GetExecutingAssembly().Location);
// Compile our code
CompilerResults result;
result = csProvider.CompileAssemblyFromSource(options, code);
if (result.Errors.HasErrors)
{
// Report back to the user that the script has errored
Console.WriteLine("Script has errored");
for (int i = 0; i < result.Errors.Count; i++)
{
Console.WriteLine("Error {0}: {1}", i+1, result.Errors[i]);
}
return null;
}
if (result.Errors.HasWarnings)
{
Console.WriteLine("Script has warnings");
}
return result.CompiledAssembly;
}
static void RunScript(Assembly script)
{
foreach (Type type in script.GetExportedTypes())
{
foreach (Type iface in type.GetInterfaces())
{
if (iface == typeof(ScriptingInterface.IScriptType1))
{
ConstructorInfo constructor = type.GetConstructor(System.Type.EmptyTypes);
if (constructor != null && constructor.IsPublic)
{
ScriptingInterface.IScriptType1 scriptObject = constructor.Invoke(null) as ScriptingInterface.IScriptType1;
if (scriptObject != null)
{
//Lets run our script and display its results
MessageBox.Show(scriptObject.RunScript(50));
}
}
}
}
}
}
public static void TestExternalCall1()
{
Console.WriteLine("Called successfully!");
}
}
}
namespace SimpleScripts
{
public class MyScriptMul5 : ScriptingInterface.IScriptType1
{
public string RunScript(ScriptingInterface.IServiceProvider serviceProvider, int value)
{
System.Console.WriteLine("Hello World! This works!");
serviceProvider.Messenger.SendMessage("Test");
}
}
}
包含宏引擎API的程序集(ScriptingInterface.dll)
宏编译器\executor
namespace ScriptingExample
{
public static class ScriptingEx
{
public static void StartScript(ScriptingInterface.IServiceProvider serviceProvider)
{
string path = @"TestScript1.cs";
// Open the file to read from.
string readText = File.ReadAllText(path);
Assembly compiledScript = CompileCode(readText);
if (compiledScript != null)
{
RunScript(serviceProvider, compiledScript);
}
}
static Assembly CompileCode(string code)
{
Microsoft.CSharp.CSharpCodeProvider csProvider = new Microsoft.CSharp.CSharpCodeProvider();
CompilerParameters options = new CompilerParameters();
options.GenerateExecutable = false;
options.GenerateInMemory = true;
options.ReferencedAssemblies.Add(Assembly.GetExecutingAssembly().Location);
//Add references to ScriptingInterface.dll
String pathToScriptingInterfaceDll = Path.Combine(Environment.CurrentDirectory, "ScriptingInterface.dll");
options.ReferencedAssemblies.Add(pathToScriptingInterfaceDll);
// Compile our code
CompilerResults result;
result = csProvider.CompileAssemblyFromSource(options, code);
if (result.Errors.HasErrors)
{
// Report back to the user that the script has errored
Console.WriteLine("Script has errored");
for (int i = 0; i < result.Errors.Count; i++)
{
Console.WriteLine("Error {0}: {1}", i+1, result.Errors[i]);
}
return null;
}
if (result.Errors.HasWarnings)
{
Console.WriteLine("Script has warnings");
}
return result.CompiledAssembly;
}
static void RunScript(ScriptingInterface.IServiceProvider serviceProvider, Assembly script)
{
foreach (Type type in script.GetExportedTypes())
{
foreach (Type iface in type.GetInterfaces())
{
if (iface == typeof(ScriptingInterface.IScriptType1))
{
ConstructorInfo constructor = type.GetConstructor(System.Type.EmptyTypes);
if (constructor != null && constructor.IsPublic)
{
ScriptingInterface.IScriptType1 scriptObject = constructor.Invoke(null) as ScriptingInterface.IScriptType1;
if (scriptObject != null)
{
//Lets run our script and display its results
MessageBox.Show(scriptObject.RunScript(50));
}
}
}
}
}
}
public static void TestExternalCall1()
{
Console.WriteLine("Called successfully!");
}
}
}
名称空间脚本示例
{
公共静态类ScriptingEx
{
公共静态无效StartScript(ScriptingInterface.IServiceProvider服务提供程序)
{
字符串路径=@“TestScript1.cs”;
//打开要从中读取的文件。
字符串readText=File.ReadAllText(路径);
汇编compiledScript=CompileCode(readText);
if(compiledScript!=null)
{
运行脚本(serviceProvider,compiledScript);
}
}
静态程序集编译代码(字符串代码)
{
Microsoft.CSharp.CSharpCodeProvider csProvider=新的Microsoft.CSharp.CSharpCodeProvider();
CompilerParameters选项=新的CompilerParameters();
options.GenerateExecutable=false;
options.GenerateInMemory=true;
options.referencedAssembly.Add(Assembly.getExecutionGassembly().Location);
//添加对ScriptingInterface.dll的引用
字符串pathToScriptingInterfaceDll=Path.Combine(Environment.CurrentDirectory,“ScriptingInterface.dll”);
op