gpt4 book ai didi

从另一个 AppDomain 访问时,c# 脚本有错误的数据

转载 作者:太空宇宙 更新时间:2023-11-03 13:36:52 25 4
gpt4 key购买 nike

我正在尝试将 C# 脚本添加到我的应用程序并决定使用 AppDomain(s) 以便我可以成功加载和卸载脚本而不会导致内存问题。我当前的代码有一个 ScriptManager,它使用观察程序在文件夹中加载脚本以检查更改:

    private static void LoadScript(string scriptPath)
{
string scriptName = Path.GetFileNameWithoutExtension(scriptPath);
AppDomain domain = AppDomain.CreateDomain(scriptName);
domains.Add(domain);
ScriptCompiler scriptCompiler = (ScriptCompiler)domain.CreateInstanceFromAndUnwrap(Assembly.GetExecutingAssembly().Location, "Milkshake.Tools.ScriptCompiler");

scriptCompiler.Compile(scriptPath);
}

它创建了我的脚本编译器的一个新的 appdomain 实例,然后尝试编译脚本代码并最终实例化脚本:

    public void Compile(string filepath)
{
string code = File.ReadAllText(filepath);

CSharpCodeProvider codeProvider = new CSharpCodeProvider(new Dictionary<String, String> { { "CompilerVersion", "v3.5" } });
CompilerParameters parameters = new CompilerParameters();
parameters.GenerateInMemory = true;
parameters.GenerateExecutable = false;

//Add references used in scripts
parameters.ReferencedAssemblies.Add(Assembly.GetExecutingAssembly().Location); //Current application ('using milkshake;')
parameters.ReferencedAssemblies.Add("System.dll");
parameters.ReferencedAssemblies.Add("System.Core.dll");
parameters.ReferencedAssemblies.Add("System.Data.dll");
parameters.ReferencedAssemblies.Add("System.Data.DataSetExtensions.dll");
parameters.ReferencedAssemblies.Add("System.Xml.dll");
parameters.ReferencedAssemblies.Add("System.Xml.Linq.dll");

CompilerResults results = codeProvider.CompileAssemblyFromSource(parameters, code);
if (results.Errors.HasErrors)
{
string error = "Error in script: " + Path.GetFileNameWithoutExtension(filepath);

foreach (CompilerError e in results.Errors)
{
error += "\n" + e;
}

Log.Print(LogType.Error, error);
}
else
{
//Successful Compile
Log.Print(LogType.Debug, "Script Loaded: " + Path.GetFileNameWithoutExtension(filepath));

assembly = results.CompiledAssembly;
type = assembly.GetTypes()[0];

//Instansiate script class.
Activator.CreateInstance(type);
}
}

现在代码实际上工作正常,它加载脚本并正确卸载它,但是当我尝试从脚本调用我的主应用程序中的方法时,它有错误的数据。例如,此脚本将打印出“Test”,然后打印出服务器上有多少玩家,最后将消息“Test”发送给所有玩家。

class TestScript
{
public TestScript()
{
Log.Print(LogType.Debug, "Test!");

//WorldServer.Sessions is missing data.
Log.Print(LogType.Debug, WorldServer.Sessions.Count);
WorldServer.Sessions.ForEach(s => s.sendMessage("Test!!"));
}
}

现在有趣的是,当我从脚本中调用它时,我的 WorldServer.Sessions.Count(WorldServer 是静态的)始终显示为 0(当我从我的主应用程序中调用它时,它显示为 1)。每次我尝试调用一个方法或从我的主应用程序获取数据时,它都会出现问题。我猜这与跨应用程序域有关,所以我真的不知道最好的方法是什么。

最佳答案

您的脚本打印为零的原因是在 .NET 应用程序域中提供了非常高级别的隔离:当在两个不同的应用程序域中加载相同的类时,两个副本的行为完全独立于彼此。除其他事项外,每个副本都有自己的一组静态变量,每个副本都运行其静态初始化代码,等等。

因此,两个应用程序域之间的通信不能通过静态变量或内存共享结构隐式完成* 。它需要明确地完成,就好像您正在与不同进程中的代码通信一样。

如果您必须与脚本交换的数据量很小,您可以使用[SetData'][1] 和[GetData`] 2避免设置更复杂的回调系统的方法。

* 虽然看起来应用域 share the virtual address space ,我无法在任何标准中找到它的证明。

关于从另一个 AppDomain 访问时,c# 脚本有错误的数据,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/18417963/

25 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com