Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Loading Interface in DLL Dynamically

Tags:

c#

interface

dll

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!

like image 724
howardlee Avatar asked Jun 28 '13 22:06

howardlee


2 Answers

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.

like image 191
terrybozzio Avatar answered Nov 12 '22 11:11

terrybozzio


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

like image 3
Alexei Levenkov Avatar answered Nov 12 '22 11:11

Alexei Levenkov