There are often times when you need to loop through all classes in an assembly and look for ones that inherit from a given interface. When you find your match you most likely are going to want to call Activator.CreateInstance which will allow you to dynamically create an instance of that object (without necessarily knowing what it is other than it implements a given interface, e.g. code to the interface).
In your loop logic if you happen to have the Interface and your implementing classes in the same assembly you can run into an instance where the MissingMethodException maybe thrown if you're trying to instantiate an interface (which you can't do, you can only instantiate the classes that implement the interface). You also will not want to instantiate abstract classes (in VB terms classes that are marked as MustInherit.. you want the classes that do the inheriting, not the base classes that have logic that hasn't been filled in yet).
The fix is to check before you activate to make sure what you're activating isn't an interface. Here is an example where a sub procedure is looking through the current assembly for IConsoleMenuItem interfaces and when it finds them it's initiating the implementing class and then doing something with it (in this case they represent dynamic menu items which are then added into a list for later usage).
VB.Net
Dim assembly As System.Reflection.Assembly = System.Reflection.Assembly.GetExecutingAssembly
Dim concreteTypeList As New List(Of Type)
For Each loadedType As Type In assembly.GetTypes
If GetType(Argus.IO.ConsoleShell.IConsoleMenuItem).IsAssignableFrom(loadedType) And loadedType.IsInterface = False And loadedType.IsAbstract = False Then
concreteTypeList.Add(loadedType)
End If
Next
If concreteTypeList.Count > 0 Then
For Each concreteType In concreteTypeList
Dim concreteMenuItem As Argus.IO.ConsoleShell.IConsoleMenuItem = DirectCast(Activator.CreateInstance(concreteType), Argus.IO.ConsoleShell.IConsoleMenuItem)
Me.MenuItems.Add(concreteMenuItem)
Next
End If
C#
System.Reflection.Assembly assembly = System.Reflection.Assembly.GetExecutingAssembly;
List concreteTypeList = new List();
foreach (Type loadedType in assembly.GetTypes)
{
if (typeof(Argus.IO.ConsoleShell.IConsoleMenuItem).IsAssignableFrom(loadedType) & loadedType.IsInterface == false & loadedType.IsAbstract == false)
{
concreteTypeList.Add(loadedType);
}
}
if (concreteTypeList.Count > 0)
{
foreach (void concreteType_loopVariable in concreteTypeList)
{
concreteType = concreteType_loopVariable;
Argus.IO.ConsoleShell.IConsoleMenuItem concreteMenuItem = (Argus.IO.ConsoleShell.IConsoleMenuItem)Activator.CreateInstance(concreteType);
this.MenuItems.Add(concreteMenuItem);
}
}
To provide context, the above comes from a program I wrote where I was implementing dynamic menu items into a console application (for use on Linux with Mono). I use my Raspberry PI as a headless security device and there are times when I want my programs to be accessible from a menu. This gives me a way to have a console menu rendering engine that doesn't change but can build the menus off of DLL's or classes inside of the executable. I add a new class, it automatically gets picked up without me having to update any menu code. This pattern essentially makes for a very basic plugin system.