Demorepo:
https://github.com/gabbersepp/csharp-dynamic-replace-class
How to use:
- Checkout
- Compile
- Delete TestLib.dll & TestLib.pdb from console/bin/Debug
- Execute console.exe through cmd
Old SO post:
Replace existing class definition at runtime with newly created type
Given:
A class in a lib:
namespace Test.TestLib
{
public class Class1
{
}
}
And a second class which creates an instance of it:
namespace console
{
public class AnotherClass
{
public void Create()
{
new Class1();
}
}
}
And a console app that calls create
:
static void Main(string[] args)
{
//...
new AnotherClass().Create();
}
Please keep in mind that only Class1
is in an extra lib. The other two classes are in the same.
What I want to do:
Replace the Assembly at runtime:
AssemblyName dynamicAssemblyName = new AssemblyName("TestLib, Version=1.0.0.0, Culture=neutral, PublicKeyToken=null");
dynamicAssembly =
AssemblyBuilder.DefineDynamicAssembly(dynamicAssemblyName, AssemblyBuilderAccess.Run);
var dynamicModule = dynamicAssembly.DefineDynamicModule("TestLib, Version=1.0.0.0, Culture=neutral, PublicKeyToken=null");
But I want not provide the type at this time. Instead I use:
AppDomain.CurrentDomain.TypeResolve += CurrentDomain_TypeResolve;
private static Assembly CurrentDomain_TypeResolve(object sender, ResolveEventArgs args)
{
Console.WriteLine("resolve type");
if (args.Name.Contains("TestLib"))
{
dynamicModule.DefineType("Test.TestLib.Class1", TypeAttributes.Class | TypeAttributes.Public).CreateType();
return dynamicAssembly;
}
return null;
}
Problem:
The event is not called when the line new AnotherClass().Create();
is executed. Instead an exception is thrown:
System.TypeLoadException: Der Typ "Test.TestLib.Class1" in der Assembly "TestLib, Version=1.0.0.0, Culture=neutral, PublicKeyToken=null" konnte nicht geladen werden
something like:
System.TypeLoadException: The type "Test.TestLib.Class1" in the assembly "TestLib, Version = 1.0.0.0, Culture = neutral, PublicKeyToken = null" could not be loaded
Please have a look into the repo for a full example.
//Edit: The demo project is written with VS2019 für .net461. I think the main concepts are the same for dotnet core. Let me know if you'd rather work with dotnet core so I can provide the project for both platforms.
//Edit2:
I debugged into the IL Code and saw, that everything runs fine until the constructor of Class1
is called:
So personally I don't think that the event handler is plugged into too late as stated by Bruno.
The official documentation states, that this event is called if the assembly is unknown:
https://learn.microsoft.com/de-de/dotnet/api/system.appdomain.typeresolve?view=netframework-4.8 The TypeResolve event occurs when the common language runtime is unable to determine the assembly that can create the requested type
I did not read that before. Hopefully someone can help me :-)
//Edit3 - possible solution:
A workaround could be, to create the types based on a list of class names. To not loose compile safety, I can use nameof
which produces no IL code. An example can be found in the repo in the branch resolveType-solution1
. But of course, not the solution I am looking for :-(