简体   繁体   English

C#-脚本编制-文件仍在使用

[英]C# - Scripting - File still being used

I'm using the CodeDomProvider class to compile my scripts in a certain application I'm developing. 我正在使用CodeDomProvider类在正在开发的某个应用程序中编译脚本。 Those are the 3 methods I'm using. 这些是我正在使用的3种方法。

public static void CompileNpcScripts(bool pLoadCompiledScripts)
    {
        Dictionary<string, DateTime> compiledScripts = new Dictionary<string, DateTime>();

        foreach (var script in System.IO.Directory.GetFiles("..\\DataSvr\\Script\\Compiled\\", "*.compiled"))
        {
            compiledScripts.Add(System.IO.Path.GetFileNameWithoutExtension(script), System.IO.File.GetLastWriteTime(script));
        }

        List<string> needCompliation = new List<string>();
        foreach (var script in System.IO.Directory.GetFiles("..\\DataSvr\\Script\\", "*.s"))
        {
            var shortname = System.IO.Path.GetFileNameWithoutExtension(script);
            if (!compiledScripts.ContainsKey(shortname) || compiledScripts[shortname] < System.IO.File.GetLastWriteTime(script))
            {
                needCompliation.Add(script);
            }
        }

        foreach (var script in needCompliation)
        {
            var shortname = System.IO.Path.GetFileNameWithoutExtension(script);

            _usableNpcScripts.Remove(shortname);

            CompilerResults results = CompileScript(ScriptType.Npc, script);
        }

        foreach (var script in System.IO.Directory.GetFiles("..\\DataSvr\\Script\\Compiled\\", "*.compiled"))
        {
            var shortname = System.IO.Path.GetFileNameWithoutExtension(script);

            if (!_usableNpcScripts.ContainsKey(shortname))
            {
                _usableNpcScripts.Add(shortname, Assembly.LoadFile(Environment.CurrentDirectory + "\\" + script));
            }
        }

        if (pLoadCompiledScripts)
        {
            foreach (KeyValuePair<string, Assembly> script in _usableNpcScripts)
            {
                GameServer.NpcScripts.Add(script.Key, (INpcScript)ScriptingTools.FindInterface(script.Value, "INpcScript"));
            }
        }
        else
        {
            foreach (var script in needCompliation)
            {
                var shortname = System.IO.Path.GetFileNameWithoutExtension(script);

                if (GameServer.NpcScripts.ContainsKey(shortname))
                {
                    GameServer.NpcScripts[shortname] = (INpcScript)ScriptingTools.FindInterface(_usableNpcScripts[shortname], "INpcScript");
                }
            }
        }
    }

    public static CompilerResults CompileScript(ScriptType pType, string pSource)
    {
        try
        {
            if (_compiler == null)
            {
                _compiler = CodeDomProvider.CreateProvider("CSharp");
                _compilerParams = new CompilerParameters();

                _compilerParams.GenerateExecutable = false;
                _compilerParams.CompilerOptions = "/optimize";
                // TODO: Should it be generated in memory?
                _compilerParams.GenerateInMemory = false;
                _compilerParams.IncludeDebugInformation = false;
                _compilerParams.ReferencedAssemblies.Add("System.dll");
                _compilerParams.ReferencedAssemblies.Add(Assembly.GetExecutingAssembly().Location);
                { }
                int lol;
            }

            _compilerParams.OutputAssembly = "Scripts\\" + pType + "\\Compiled\\" + System.IO.Path.GetFileNameWithoutExtension(pSource) + ".compiled";
            var result = _compiler.CompileAssemblyFromFile(_compilerParams, pSource);

            if (System.IO.File.Exists(_compilerParams.OutputAssembly))
            {
                System.IO.File.SetLastWriteTime(_compilerParams.OutputAssembly, System.IO.File.GetLastWriteTime(pSource));
            }

            return result;
        }
        catch
        {
            // Stil being used by the user.
            return null;
        }
    }

    public static object FindInterface(Assembly pDLL, string pInterface)
    {
        foreach (Type type in pDLL.GetTypes())
        {
            if (type.GetInterface(pInterface, true) != null)
                return pDLL.CreateInstance(type.FullName);
        }

        return null;
    }

The boolean "pLoadCompiledScripts" is to tell the program if the script should be reloaded or inserted . 布尔值“ pLoadCompiledScripts”用于告诉程序是否应重新加载插入脚本。 GameServer's NpcScripts dictionairy is just a collection of the interface INpcScript. GameServer的NpcScripts字典只是INpcScript接口的集合。

Now. 现在。 On the initla load I call the following: CompileNpcScripts(true), so it will check for the files that need compliation, will recompile them and then will load all of them to the dictionairy. 在initla加载时,我调用以下命令:CompileNpcScripts(true),因此它将检查需要编译的文件,将对其进行重新编译,然后将所有文件加载到字典中。 I also have a FileWatcher class which watches the Script folder for changes. 我还有一个FileWatcher类,它监视Script文件夹中的更改。 Once the event is raised, I call CompileNpcScripts(false), so it will reload existing scripts. 引发事件后,我将调用CompileNpcScripts(false),以便它将重新加载现有脚本。 However, the CompileScript method returns null because the file "[name].compiled" is being used by another process. 但是,由于另一个进程正在使用文件“ [name] .compiled”,因此CompileScript方法返回null。 Why is it like so an dhow can I solve it? 为什么这样单调无味地解决呢? Thanks. 谢谢。

The issue might be one of two things. 问题可能是两件事之一。

First, check your FileWatcher class and make sure it's not holding onto any of the files it's watching (like accessing the last modified date property or whatever the case may be). 首先,检查您的FileWatcher类,并确保它没有保留正在监视的任何文件(例如,访问上次修改的date属性或任何情况)。

Secondly, the compiler might still be holding onto the scripts after it gets down compiling them. 其次,编译器在开始编译脚本后可能仍会保留它们。 I would try and dispose of the compiler and rebuild it each time I went to recompile the scripts. 每当我去重新编译脚本时,我都将尝试处置该编译器并对其进行重建。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM