I was trying to learn how to dynamically load DLL into a C# program. The idea is that the DLL will contain an interface and several different implementations of the interface so that if I want to add new implementations I don't have to recompile my whole project.
So I created this test. Here is my DLL file:
namespace TestDLL
{
public interface Action
{
void DoAction();
}
public class PrintString : Action
{
public void DoAction()
{
Console.WriteLine("Hello World!");
}
}
public class PrintInt : Action
{
public void DoAction()
{
Console.WriteLine("Hello 1!");
}
}
}
And in my main program I tried to do something like this:
static void Main(string[] args)
{
List<Action> actions = new List<Action>();
Assembly myDll = Assembly.LoadFrom("TestDLL.dll");
Type[] types = myDll.GetExportedTypes();
for (int i = 0; i < types.Length; i++)
{
Type type = types[i];
if (type.GetInterface("TestDLL.Action") != null && type != null)
{
Action new_action = myDll.CreateInstance(type.FullName) as Action;
if (new_action != null)
actions.Add(new_action);
else
Console.WriteLine("New Action is NULL");
}
}
foreach (Action action in actions)
action.DoAction();
}
And the problem I am having is, even though
type.FullName
contains the right value ("TestDLL.PrintString", etc),
the line
myDll.CreateInstance(type.FullName) as Action
always returns null.
I am not exactly sure what the problem is, or how I could work around it.
As in the example, I would like to be able to add new implementations of Action to the DLL, and have the main Program invoke DoAction() on each of these implementation, without having to recompile the original program. Hope this makes sense!
By your Main implementation you better do this
List<object> actions = new List<object>();
Assembly myDll = Assembly.LoadFrom("TestDLL.dll");
Type[] types = myDll.GetTypes();
for (int i = 0; i < types.Length; i++)
{
Type type = myDll.GetType(types[i].FullName);
if (type.GetInterface("TestDLL.Action") != null)
{
object obj = Activator.CreateInstance(type);
if (obj != null)
actions.Add(obj);
}
}
foreach (var action in actions)
{
MethodInfo mi = action.GetType().GetMethod("DoAction");
mi.Invoke(action, null);
}
and you should wrap this up in a try/catch block.
And when you write Action(since you dont have a reference set to your assembly), like in List<Action>
,this Action is refering to the Action delegate.
Most likely your Action
is defined in both main and "other" assembly and you are casting to the wrong one.
Usually shared interfaces are defined in separate assembly ("SDK") and linked both from main application and plug-in assemblies. Sharing interface via source does not work since identity of class includes assembly name along with type name.
See for more info: Cannot get types by custom attributes across assemblies
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With