我试图在一个循环的目录中执行cs脚本。每次脚本更改(或者如果它是新的)它都会被加载并执行。但是我第二次尝试加载脚本时收到错误:
Access to the path 'C:\Users\Admin\AppData\Local\Temp\CSSCRIPT\Cache\647885655\hello.cs.compiled' is denied.
我试图做的是:
static Dictionary<string, string> mFilePathFileHashes = new Dictionary<string, string>();
public static void LoadFromDir(string dir)
{
foreach (string filepath in Directory.GetFiles(dir))
{
string hash = GetMD5HashFromFile(filepath); //Generate file hash
if (mFilePathFileHashes.Contains(new KeyValuePair<string, string>(filepath, hash))) continue; //Skip if it hasn't changed
if (mFilePathFileHashes.ContainsKey(filepath))
{ //Hash changed
mFilePathFileHashes[filepath] = hash;
}
else //This is the first time this file entered the loop
mFilePathFileHashes.Add(filepath, hash);
//Load the script
IScript script = CSScript.Load(filepath)
.CreateInstance("Script")
.AlignToInterface<IScript>();
//Do stuff
script.AddUserControl();
}
protected static string GetMD5HashFromFile(string fileName)
{
FileStream file = new FileStream(fileName, FileMode.Open);
MD5 md5 = new MD5CryptoServiceProvider();
byte[] retVal = md5.ComputeHash(file);
file.Close();
StringBuilder sb = new StringBuilder();
for (int i = 0; i < retVal.Length; i++)
{
sb.Append(retVal[i].ToString("x2"));
}
return sb.ToString();
}
在“加载脚本”部分,它会抛出错误。所以我read up对它进行了一些尝试:
//Load the script
string asmFile = CSScript.Compile(filepath, null, false);
using (AsmHelper helper = new AsmHelper(asmFile, "temp_dom_" + Path.GetFileName(filepath), true))
{
IScript script = helper.CreateAndAlignToInterface<IScript>("Script");
script.AddUserControl();
//helper.Invoke("Script.AddUserControl");
}
因为该页面说Script is loaded in the temporary AppDomain and unloaded after the execution. To set up the AsmHelper to work in this mode instantiate it with the constructor that takes the assembly file name as a parameter
但是这不会与界面对齐:Type 'Script' in Assembly 'hello.cs, Version=0.0.0.0, Culture=neutral, PublicKeyToken=null' is not marked as serializable.
这甚至意味着什么,为什么它需要可序列化?
如果我切换到helper.Invoke
行,我会得到一个NullReferenceException。
剧本:
using System;
using System.Windows.Forms;
using CSScriptTest;
class Script : CSScriptTest.IScript
{
public void AddUserControl()
{
Form1.frm.AddUserControl1(this, "test_uc_1");
}
}
所以最后一个错误可能是因为我从未真正与接口对齐,或者因为我从主AppDomain外部调用静态方法(我真的不知道)。
有没有办法让这个工作?
答案 0 :(得分:0)
好吧,它的工作原理是将我想要操作的对象传递给接口'方法,如下所示:
using (var helper = new AsmHelper(CSScript.Compile(filepath), null, false))
{
IScript script = helper.CreateAndAlignToInterface<IScript>("Script");
script.AddUserControl(Form1.frm);
}
脚本继承自MarshalByRefObject
,如下所示:
using System;
using System.Windows.Forms;
using CSScriptTest;
class Script : MarshalByRefObject, CSScriptTest.IScript
{
public void AddUserControl(CSScriptTest.Form1 host)
{
host.AddUserControl1(this, "lol2");
}
}
MSDN sais MarshalByRefObject Enables access to objects across application domain boundaries in applications that support remoting.
所以我觉得这很有意义..但是我有什么方法可以将我的主应用程序的方法暴露给脚本吗?
通过在主程序中继承MarshalByRefObject
似乎不可能,如下所示:
public class CTestIt : MarshalByRefObject
{
public static CTestIt Singleton;
internal static void SetSingleton()
{ //This method is successfully executed before we start loading scripts
Singleton = new CTestIt();
Console.WriteLine("CTestIt Singleton set");
}
public static void test()
{
//Null reference when a script calls CSScriptTest.CTestIt.test();
Singleton.test_member();
}
public void test_member()
{
Console.WriteLine("test");
}
}