-4

I want to get the list of classes in an assembly, as an output i want a List[Interface] not a List[string], as "Interface" is the interface from which inherits the classes of my assembly. I don't know if my question makes sense but if any one has the answer i would very much thankful. I already tried this solution: List of classes in an assembly, but it gives a list[string] containing the classes namesso it didn't help because i need the list of the classes that inherits from my interface. Thank you and have a nice day all :)

As an edit for my question, I used activator.createinstance(type t) to create instances of my classes so here is the code :

   Assembly assembly = typeof(Interface1<double, double>).Assembly;

   List<Interface> Classes = new List<Interface>();

   foreach (Type type in assembly.GetExportedTypes())

   {
      var Attributes = type.GetCustomAttributes<FilterAttribute>();
      //select the classes with attribute [Filter]

      if (Attributes.Any())

      {
                TypeOfFilters.Add(type);

      }

      foreach (var i in TypeOfFilters)

      {
            var inst = Activator.CreateInstance(i);

            Classes.Add((Interface) inst);


      }

   }

i get the error "System.IO.FileNotFoundException : Could not load file or assembly"

Community
  • 1
  • 1
AMI
  • 97
  • 12
  • 5
    `but it didn't work for me! `. OK. How? – Nikhil Agrawal Apr 25 '17 at 10:03
  • 3
    This is either a dupe of the question you linked to, unless you specify how it didn't work. Or it is Off topic because you haven't provided all of the relevant information in your post. Consider adding a [MCVE] so it is clear what your issue is. You can [edit] your question to add this information in. – TheLethalCoder Apr 25 '17 at 10:05
  • 1
    What do you mean by "didn´t work"? Do you get an exception? Eunexpected results? What did you expect instead? Please show what you´ve tried any where you´re stuck. – MakePeaceGreatAgain Apr 25 '17 at 10:05
  • it gave me a List, it's not what i'm looking for. – AMI Apr 25 '17 at 10:05
  • 2
    @ABIR And what are you looking for? – TheLethalCoder Apr 25 '17 at 10:06
  • @ABIR: If I get you correctly, you say you have an interface `IX` that all classes within your assembly inherit from. Thus, you want a `List` as a result. However, that would mean each discovered class would have to be *instantiated*, so you would get a list with *one instance of each type in your assembly* - is that what you want? – O. R. Mapper Apr 25 '17 at 10:07
  • Could you paste the exact code you're using? For example, your List is named `classes`, but later referenced as `Classes`. Also, what is the full exception you are getting, including assembly names? The name usually comes after "Could not load file or assembly" – ColinM Apr 26 '17 at 21:26
  • I finally solved the issue i added a parametreless constructor to each class that inherits from my Interface, as for the error "System.IO.FileNotFoundException : Could not load file or assembly" it was due to the fact that "System.ComponentModel.Composition.CodePlex " copy local was set to false. So both methods work perfectly!! sorry for the delay response and thank you very much @ColinM. – AMI Apr 27 '17 at 14:34
  • Excellent news, glad you got it sorted & enjoy your plugin system – ColinM Apr 27 '17 at 14:37

2 Answers2

2

Here's a little class I whipped up some weeks back when I was bored, this does what you're asking of - if I understand the question correctly.

Your applications must implement IPlugin, and must be dropped in a "Plugins" folder in the executing directory.

public interface IPlugin
{
    void Initialize();
}
public class PluginLoader
{
    public List<IPlugin> LoadPlugins()
    {
        List<IPlugin> plugins = new List<IPlugin>();

        IEnumerable<string> files = Directory.EnumerateFiles(Path.Combine(Directory.GetCurrentDirectory(), "Plugins"),
            "*.dll",
            SearchOption.TopDirectoryOnly);

        foreach (var dllFile in files)
        {
            Assembly loaded = Assembly.LoadFile(dllFile);

            IEnumerable<Type> reflectedType =
                loaded.GetExportedTypes().Where(p => p.IsClass && p.GetInterface(nameof(IPlugin)) != null);

            plugins.AddRange(reflectedType.Select(p => (IPlugin) Activator.CreateInstance(p)));
        }

        return plugins;
    }
}

Following from Paul's recommendation in the comments, here's a variation using MEF, referencing the System.ComponentModel.Composition namespace.

namespace ConsoleApplication18
{
    using System;
    using System.ComponentModel.Composition;
    using System.ComponentModel.Composition.Hosting;
    using System.IO;
    using System.Linq;

    public interface IPlugin
    {
        void Initialize();
    }
    class Program
    {
        private static CompositionContainer _container;
        static void Main(string[] args)
        {
            AggregateCatalog catalog = new AggregateCatalog();
            catalog.Catalogs.Add(new DirectoryCatalog(Path.Combine(Directory.GetCurrentDirectory(), "Plugins")));

            _container = new CompositionContainer(catalog);

            IPlugin plugin = null;
            try
            {
                _container.ComposeParts();

                // GetExports<T> returns an IEnumerable<Lazy<T>>, and so Value must be called when you want an instance of the object type.
                plugin = _container.GetExports<IPlugin>().ToArray()[0].Value;
            }
            catch (CompositionException compositionException)
            {
                Console.WriteLine(compositionException.ToString());
            }

            plugin.Initialize();
            Console.ReadKey();
        }
    }
}

and the DLL file - also referencing the System.ComponentModel.Composition namespace to set the ExportAttribute

namespace FirstPlugin
{
    using System.ComponentModel.Composition;

    [Export(typeof(IPlugin))]
    public class NamePlugin : IPlugin
    {
        public void Initialize() { }
    }
}
ColinM
  • 2,622
  • 17
  • 29
  • 2
    If this is what ABIR is wanting I would use MEF(Managed Extensibility Framework) instead of creating the instances by yourself via Activator-class. MEF mechanism was created for the purpose of loading and instantiating classes that implement a specified interface at runtime and is a safer approach. – Paul Weiland Apr 25 '17 at 13:41
  • Thanks for that @PaulWeiland, I've only ever used the `Activator` and `Delegate` approaches, but will have to take a look at MEF too – ColinM Apr 25 '17 at 13:45
  • I'm using it for a Plug-In-Framework im working on. Hacked some code together with Activator.CreateInstance first until a workmate of mine directed me to MEF. That made my life a lot easier. – Paul Weiland Apr 25 '17 at 13:47
  • 2
    For Op: Here's a nice little brief tutorial on MEF, the benefits are definitely seen here rather than using Activators and creating your own logic to pick up your plugins from a specific directory. https://www.codeproject.com/Articles/188054/An-Introduction-to-Managed-Extensibility-Framework#4 – ColinM Apr 25 '17 at 14:17
  • thank you for the answers @ColiM , this is exactly what i need. but i get the error "System.IO.FileNotFoundException : Could not load file or assembly" the problem i think is with "Directory.GetCurrentDirectory()" is gives me a totally different directory "C:\Users\AppData\Local\JetBrains\Installations\ReSharperPlatformVs14" instead of the one containing the assembly. – AMI Apr 26 '17 at 13:17
  • Ensure the plugins folder is the correct path, and possibly debug the path – ColinM Apr 26 '17 at 13:21
  • Also, which code above are you using, MEF or Activator? If you're getting the ReSharper directory then are you creating a ReSharper plugin? – ColinM Apr 26 '17 at 13:44
  • i already tried activator and it gives me the error "System.MissingMethodException : No parameterless constructor defined for this object. " francly i couldn't resolve it i didn't understand what is the problem so i tried with the other solution ! where exactly do i need to create the plugins folder? – AMI Apr 26 '17 at 15:29
  • The MissingMethodException would have been due to a direct copy of the code I posted, so you essentially would have been calling `Initialize` on your plugin class - which doesn't implement that method. The architecture of the plugins system I think is down to you ultimately, but the plugins folder can be anywhere as long as you have a link to that path **and** it contains the Dll files which have the classes that implement your plugin interface **AND** use the `ExportAttribute` to allow the `CompositionContainer` to import. – ColinM Apr 26 '17 at 15:45
  • @ABIR, let's continue the discussion here http://chat.stackoverflow.com/rooms/142754/list-of-classes-in-an-assembly-c – ColinM Apr 26 '17 at 17:14
  • @ColinM, i'm sorry it seems that i can not speak in chat rooms because I must have 20 reputation on Stack Overflow to talk there, i only have 15 :/ – AMI Apr 26 '17 at 18:36
  • Still can't i'm sorry!! my reutation is still 15 in chat rooms!! – AMI Apr 26 '17 at 18:57
  • @ABIR Can you update your question and provide more information as to how you're using the code above? – ColinM Apr 26 '17 at 19:07
0

If I understand your question correctly it should be something like that:

var list = System.Reflection.Assembly.GetTypes().Where(x => typeof(IYourInterface).IsAssignableFrom(x)).ToList();
nocodename
  • 1,246
  • 9
  • 15