Delete dll file after unloading an AppDomain

I’m currently trying to make a game engine, trying to replicate piece-by-piece unity functions,
for loading some scripts, i have no problem, but when i have to reload them, the compilation with mono fail, telling me DLL is already accessed, or the DLL file can’t be deleted.

Here is my code:

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Reflection;
using System.IO;
using System.Runtime.InteropServices;
using System.Threading;
using System.Diagnostics;
using System.Security.Policy;
using System.Security;
using System.Security.Permissions;

public class Proxy : MarshalByRefObject
    {
        public Assembly GetAssembly(string assemblyPath)
        {
            try
            {
                byte[] response = new System.Net.WebClient().DownloadData(assemblyPath);
                return Assembly.ReflectionOnlyLoad(response);
            }
            catch (Exception)
            {
                return null;
            }
        }
        public Assembly GetAssembly2(string assemblyPath, AppDomain domain)
        {
            try
            {
                byte[] bytesDLL = new System.Net.WebClient().DownloadData(assemblyPath);
                return domain.Load(bytesDLL);
            }
            catch (Exception)
            {
                return null;
                // throw new InvalidOperationException(ex);
            }
        }
        public Assembly GetAssemblyByName(AssemblyName name, AppDomain domain)
        {
            return domain.ReflectionOnlyGetAssemblies().
                   SingleOrDefault(assembly => assembly.GetName() == name);
        }
    }

class Program
{
    public static AppDomain domain;
    public static Assembly      assembly;
    public static Type          type;
    public static String        dllPath;
    public static String        scriptPath;
    public static String        className;
    public static String        file;
    public static dynamic       instance;
    private static bool Compile(String path, out String dir)
    {

            ProcessStartInfo start = new ProcessStartInfo();
            dir = Path.GetDirectoryName(Assembly.GetExecutingAssembly().Location);
            dir = Path.Combine(dir, Path.GetFileNameWithoutExtension(path) + ".dll");
            if (File.Exists(dir))
            {
                Console.WriteLine("???????");
                File.Delete(dir);
                Console.WriteLine("???????2");
            }
            start.FileName = Path.Combine(Path.GetDirectoryName(Assembly.GetExecutingAssembly().Location), "Monolibmono4.5mcs.exe");
            start.UseShellExecute = false;
            start.RedirectStandardError = true;
            start.RedirectStandardOutput = true;
            start.Arguments = """ + path + "" " + "/target:library" + " " + "/out:" + """ + dir + """; //+ " " + "/reference:OctogonEngine.dll" + " /reference:AssimpNet.dll";
            using (Process process = Process.Start(start))
            {
                using (StreamReader reader = process.StandardError)
                {
                    string result = reader.ReadToEnd();
                    Console.WriteLine(result);
                }
                using (StreamReader reader = process.StandardOutput)
                {
                    string result = reader.ReadToEnd();
                    Console.WriteLine(result);
                }
            }
            Console.WriteLine("compilation ok");
            return (true);
    }

    public static void Unload()
    {
        FileStream[] streams = null;
        if (assembly != null)
            streams = assembly.GetFiles();

        instance = null;
        GC.Collect();
        GC.WaitForPendingFinalizers();
        GC.Collect();
        type = null;
        assembly = null;
        AppDomain.Unload(domain);
        assembly = null;
        if (streams != null)
        {
            for (int i = 0; i < streams.Length; i++)
            {
                streams[i].Dispose();
            }
        }
        GC.Collect();
        GC.WaitForPendingFinalizers();
        GC.Collect();
        Directory.Delete(cachePath, true);
        return ;
    }
    static Assembly GetAssemblyByName(string name, AppDomain domain)
    {
        return domain.GetAssemblies().
               SingleOrDefault(assembly => assembly.GetName().Name == name);
    }
    public static String cachePath = "./cache/";

    public static void Load()
        {
            Directory.CreateDirectory(cachePath);
            if (Compile(scriptPath, out Program.dllPath))
            {
                if (File.Exists(Program.dllPath))
                {
                    className = Path.GetFileNameWithoutExtension(Program.dllPath);

                    AppDomainSetup setup = new AppDomainSetup();
                    setup.ApplicationBase = AppDomain.CurrentDomain.BaseDirectory;
                    setup.ShadowCopyFiles = "true";
                    setup.CachePath = cachePath;
                    domain = AppDomain.CreateDomain(className, null, setup);
                    domain.DoCallBack(() => AppDomain.CurrentDomain.Load(AssemblyName.GetAssemblyName("test.dll")));
                    var assemblyLoader = (Proxy)domain.CreateInstanceAndUnwrap(typeof(Proxy).Assembly.FullName, typeof(Proxy).FullName);
                    assembly = assemblyLoader.GetAssembly(Program.dllPath);
                    /*if (assembly == null)
                    {
                        Console.WriteLine("damn");
                    }*/
                    if (assembly != null)
                    {
                        type = assembly.GetType(className);
                    }
                    if (File.Exists(scriptPath))
                        Program.file = File.ReadAllText(scriptPath);
                }
            }
        }
        static bool check = false;

    static void AppDomainInit(string[] args)
    {
        if (!File.Exists(args[0]))
        {
            return;
        }
    }
    public static void init(String scriptPath)
    {
        if (File.Exists(scriptPath))
        {
            Program.file = File.ReadAllText(scriptPath);
            Program.scriptPath = scriptPath;
            Program.Load();
        }
    }


    static void Main(string[] args)
    {
        Program.init(Path.Combine(Path.GetDirectoryName(Assembly.GetExecutingAssembly().Location), "test.cs"));
        Program.Unload();
       //here is the crash :/
       File.Delete(Program.dllPath);
        Console.WriteLine("???");
    }
}

(To test, you may need to copy mono in the executing directory, wich can be found at : http://www.mono-project.com/download/)

Does anybody have a clue on what i can do to either, force delete that dll file, or to make that file accessible for deletion?

If not, does somebody have a clue on the way unity load and reload scripts, how to make it the good way?


Source: dll

Leave a Reply