I'm experimenting with a plugin architecture using C# and dotnet. What I've discovered is that any instance created this way doesn't get collected until the application closes.
My original thought was to load each object and call a registration method, then allow it to die. The registration method would pass back the information needed to know when it should be loaded in the future and create a new instance at that time. This would prevent me from keeping 50 or so objects alive when not in use.
Putting a simple System.Diagnostics.Debug.Writeline in the constructor and finalizer of the classes this first loop through does not destroy any objects. Only when I close the application do any finalizer calls happen. If I do an experiment where I have an internal IProduct instance and load several instances to that I get 5 constructor calls and once I close 5 finalizer calls.
For the below I created 2 different DLL's with 1 class each implementing the interface. So I get a Class1 Constructor call and a Class2 Constructor call. But only get destructor calls when closing.
My initial expectations where that the finalizer would be called once the IProduct myDLL fell out of scope (iterating through/leaving the for loop) Or worst case the function itself. This is pared down to have no data pass from the loaded dll to the main program to ensure I'm not keeping anything alive through hanging onto a reference, but I'm still seeing the same results.
void LoadProductPlugins()
{
string[] sFiles = Directory.GetFiles(Directory.GetCurrentDirectory() + "\\dll", "*.dll", SearchOption.TopDirectoryOnly);
foreach (string strDll in sFiles)
{
Assembly assy = Assembly.LoadFile(strDll);
Type[] types = (from t in assy.GetExportedTypes()
where !t.IsInterface && !t.IsAbstract
where typeof(IProduct).IsAssignableFrom(t)
select t).ToArray();
for (int i = 0; i < types.Length; i++)
{
IProduct myDLL = (IProduct) Activator.CreateInstance(types[i]);
}
}
}
There is no difference in lifespan management of an object whether it is created via regular new
, CreateInstance
or any other method one can come up with. An object will be collected when GC is needed and the particular object is no longer reachable.
Notes: