views:

163

answers:

2

Is it possible to replace method ForEach() usage with Select() or something else to write next code in one string with nested extension methods? OR maybe there are another ways to improve the algorithm?

var list = new List<IStatementParser>();

System.IO.Directory.GetFiles(path, "*.dll")
    .ForEach(f => System.Reflection.Assembly.LoadFrom(f)
     .GetTypes()
     .Where(t => !t.IsInterface && typeof(IFoo).IsAssignableFrom(t))
     .ForEach(t => list.Add((IFoo)Activator.CreateInstance(t))));

return list.ToDictionary(k => k.Name, v => v.GetType());

It loads all classes from assemblies in path that implements IFoo and adds them to Dictionary<string, Type> where string is IFoo.Name

+3  A: 

I don't see any need for an intermediate List here at all - you can just do this:

return (from dll in Directory.GetFiles(path, "*.dll")
        let asm = Assembly.LoadFrom(dll)
        from t in asm.GetTypes()
        where !t.IsInterface && typeof(IFoo).IsAssignableFrom(t)
        select (IFoo)Activator.CreateInstance(t)
       ).ToDictionary(foo => foo.Name, foo => foo.GetType())

By the way, you might also want to check whether a type is abstract before trying to instantiate it.

Pavel Minaev
Could you please describe what for do you use 'let'? Bryan Watts below doesn't
abatishchev
It's a convenience/readability thing, not strictly necessary.
Pavel Minaev
+3  A: 
var foos =
    from dllFile in Directory.GetFiles(path, "*.dll")
    from type in Assembly.LoadFrom(dllFile).GetTypes()
    where !type.IsInterface && typeof(IFoo).IsAssignableFrom(type)
    select (IFoo) Activator.CreateInstance(type);

return foos.ToDictionary(foo => foo.Name, foo => foo.GetType());
Bryan Watts
You need a foo => foo.GetType() parameter as the value delegate in the ToDictionary call. Otherwise, an excellent answer.
Joe Chung
I need only to clarify usage of 'let' above and I'm ready to accept your answer. And btw, I don't need Dictionary<string, IFoo>, I need Dictionary<string, Type> where Type = IFoo (I edited initial post) -- because this dictionary will be used by FooFactory to create an instance of IFoo by request, that may doesn't happen at all, in current session.
abatishchev
Edited to include the .GetType() call. The let clause in @Pavel's answer is a style thing - you don't need to have it, but he may perceive it as more clear.
Bryan Watts