How to clean up old versions of assemblies with the same name when dynamically compiling code multiple times?

tfsss 41 Reputation points
2023-10-13T02:58:08.6933333+00:00

Hi guys,

I'm using dynamic compilation in .net 7 and the current code is like this:

 
private void button1_Click(object sender, EventArgs e)
{
    Assembly[] assemblies = AppDomain.CurrentDomain.GetAssemblies();

    string code = @"public class Person
                    {
                        public static string SayName()=>""fan"";
                    }";

    AssemblyLoadContext assemblyLoadContext = new AssemblyLoadContext("alc", true);
    var compiler = new Compiler();
    var assembly = compiler.Compile(code,assemblyLoadContext, Assembly.Load(new AssemblyName("System.Runtime")), typeof(object).Assembly);
    assemblyLoadContext.Unload();

}

public class Compiler
{
    public Assembly Compile(string text, AssemblyLoadContext assemblyLoadContext, params Assembly[] referencedAssemblies)
    {
        var references = referencedAssemblies.Select(it => MetadataReference.CreateFromFile(it.Location));
        var options = new CSharpCompilationOptions(OutputKind.DynamicallyLinkedLibrary);
        var assemblyName = "DynamicAssembly";
        var syntaxTrees = new SyntaxTree[] { CSharpSyntaxTree.ParseText(text) };
        var compilation = CSharpCompilation.Create(assemblyName, syntaxTrees, references, options);
        using (var stream = new MemoryStream())
        {
            var compilationResult = compilation.Emit(stream);
            if (compilationResult.Success)
            {
                stream.Seek(0, SeekOrigin.Begin);
                return assemblyLoadContext.LoadFromStream(stream);
            }
            return null;
        }
    }
}  

It's fine when compiled only once, but from time to time I need to add new content to the code, which causes some problems.

First, CSharpCompilation.Create will cause Process Memory to increase and will not fall back (measuring by sight). This is unacceptable if dynamic compilation occurs many times.

Second, the compiled assembly will be added to the CurrentDomain assembly. Multiple assemblies with the same name will also cause some trouble for my use.

User's image

I'm struggling with this, any ideas are appreciated!

C#
C#
An object-oriented and type-safe programming language that has its roots in the C family of languages and includes support for component-oriented programming.
11,404 questions
0 comments No comments
{count} votes

Accepted answer
  1. Viorel 121.3K Reputation points
    2023-10-13T05:49:53.5766667+00:00

    Check if the assembly is unloaded in this test:

    private void button1_Click( object sender, EventArgs e )
    {
        Assembly[] assemblies = AppDomain.CurrentDomain.GetAssemblies( );
    
        WeakReference awr;
    
        ExecuteAndUnload( out awr );
    
        for( int i = 0; awr.IsAlive && ( i < 10 ); i++ )
        {
            GC.Collect( );
            GC.WaitForPendingFinalizers( );
        }
    }
    
    
    [MethodImpl( MethodImplOptions.NoInlining )]
    static void ExecuteAndUnload( out WeakReference alcWeakRef )
    {
        string code = @"public class Person
                {
                    public static string SayName()=>""fan"";
                }";
    
        AssemblyLoadContext assemblyLoadContext = new AssemblyLoadContext( "alc", true );
        alcWeakRef = new WeakReference( assemblyLoadContext, trackResurrection: true );
        var compiler = new Compiler( );
        var assembly = compiler.Compile( code, assemblyLoadContext, Assembly.Load( new AssemblyName( "System.Runtime" ) ), typeof( object ).Assembly );
        assemblyLoadContext.Unload( );
    

    See:


0 additional answers

Sort by: Most helpful

Your answer

Answers can be marked as Accepted Answers by the question author, which helps users to know the answer solved the author's problem.