I want to allow developers that use my product to be able to extend the product by implementing an interface and then just dropping the assembly into the executing folder. How should I go about finding these types, do I have to run thru every single DLL in the folder or can I avoid those that are part of the original application?
4 Answers
Why arent you using microsoft's solutions?
As far as i understand, it solves exactly what youre looking for

- 2,113
- 14
- 11
-
I am thinking about using MEF, but I wanted the simplest implementation and MEF is a step up in complexity. – Noel May 30 '12 at 05:14
-
1i think that using it with the simplest possibilites will be easier to add/maintain than writing your own dependency injection solutions, but thats your choice, of course – YavgenyP May 30 '12 at 05:57
-
I have one other reason for not using MEF and that is...the underlying component is reusable. When I started developing it, I wanted it to be friendly to any IoC container, and not dependent on a specific implementation. Right now I can use my component in a application and if I use and IoC container I can use the configuration to wire up my extensions. But I don't really like configuration for things that don't change, so I wanted an alternative where the extensions could be loaded automatically if the implementation dlls were dumped in the bin. – Noel May 30 '12 at 21:22
You could either put the new assemblies into a different folder (call or plugins or extensions for example), then instantiate them at runtime; or, maintain a list of the product assemblies and use Path.GetFiles and remove any assemblies that appear in the list.

- 9,335
- 10
- 49
- 81
-
Like what? Wouldn't keeping extended assemblies separated from core assemblies make everything easier and neater? – Steve May 30 '12 at 05:06
-
Does not seem like you have done this before :) Try it. (the problem is with 'same' dependencies in the main app folder and your plugin folder, 2 copies will work, but hardly a good solution). – leppie May 30 '12 at 05:08
-
-
1@Noel: Go with the MEF suggestion. Will save you quite a few headaches :) – leppie May 30 '12 at 05:29
I use this for user-defined tools.
private static void getImplementedTypes(Type baseType, Assembly assembly, IList<Type> list) {
Type[] types = assembly.GetExportedTypes();
foreach (Type t in types) {
if (baseType.IsInterface) {
Type[] interfaces = t.GetInterfaces();
foreach (Type i in interfaces) {
if (i == baseType) list.Add(t);
}
}
else {
if ((!list.Contains(t)) && (t.IsSubclassOf(baseType)) && (!t.IsAbtract)) {
list.Add(t);
}
}
}
return n;
}
In a loop i go through all DLLs (or EXEs) found by Directory.GetFiles in the tool directory:
Assembly assembly = Assembly.LoadFile("toolbox.dll");
List<Type> types = new List<Type>();
getImplementedTypes(typeof(ToolBase), assembly, types);
ToolBase theTool = Activator.CreateInstance(type, true) as ToolBase;
This works for interfaces as well as base classes.
I don't know a way find implemented classes in a different way. This may take some time. So if you know which DLLs to search, only loop through them.

- 8,344
- 9
- 54
- 80
In the end I elected to simply load up and search thru all dlls that I found in the bin. Here is most of the code. the key function it the "IsAssignableToGenericType" function which finds the generic Interface I am looking for.
I beleive this is the link that provided most of the solution Implementations of interface through Reflection
static AssemblyLocator()
{
AllDlls = GetAllDlls();
SubscribersInBin = GetSubscribersInBin();
}
public static IEnumerable<Type> TypesImplementingInterface(Assembly[] assemblies, Type desiredType)
{
return assemblies
.SelectMany(assembly => assembly.GetTypes())
.Where(type => IsAssignableToGenericType(type, desiredType));
}
public static bool IsAssignableToGenericType(Type givenType, Type genericType)
{
if (givenType == null) throw new ArgumentNullException("givenType");
if (genericType == null) throw new ArgumentNullException("genericType");
var interfaceTypes = givenType.GetInterfaces();
foreach (var it in interfaceTypes)
{
if (it.IsGenericType)
{
if (it.GetGenericArguments()[0].Name.Equals(genericType.GetGenericArguments()[0].Name))
return true;
}
}
Type baseType = givenType.BaseType;
if (baseType == null) return false;
return (baseType.IsGenericType &&
baseType.GetGenericTypeDefinition() == genericType) ||
IsAssignableToGenericType(baseType, genericType);
}
private static ReadOnlyCollection<string> GetAllDlls()
{
string binFolder = Path.GetDirectoryName(Assembly.GetExecutingAssembly().Location);
IList<string> dllFiles = Directory.GetFiles(binFolder, "*.dll", SearchOption.TopDirectoryOnly).ToList();
return new ReadOnlyCollection<string>(dllFiles);
}
private static ReadOnlyCollection<Type> GetSubscribersInBin()
{
IList<Assembly> assembliesFoundInBin = new List<Assembly>();
foreach (var item in AllDlls)
{
var assembly = System.Reflection.Assembly.LoadFrom(item);
assembliesFoundInBin.Add(assembly);
}
var typesInBin = TypesImplementingInterface(assembliesFoundInBin.ToArray(), typeof(ISubscriber<T>));
return new ReadOnlyCollection<Type>(typesInBin.ToList<Type>());
}