0

I have a plugin system and my plugin class looks like this

namespace CSV_Analyzer_Pro.Core.PluginSystem 
{
    public interface IPlugin
    {
        string Name { get; }
        string Version { get; }
        string TargetVersion { get; }
        string Description { get; }
        string TargetFramework { get; }
        void Action();
    }
}

In my loader class I have a function that calls the Action method of each plugin which is called when the application is loaded

public void Init() 
{
    if(Plugins != null) 
    {
        Plugins.ForEach(plugin => plugin.Action());
    }
}

I would like to use a similiar method so I can call in my application

loader.getByTargetFramework("UI");

This should get all plugins targeting the "UI" framework and put them in a list and then I can iterate through the methods

This is what I have so far

public void GetPluginByTargetFramework(string framework) 
{
    //Get all plugins
    List<IPlugin> frameworkPlugs = new List<IPlugin>();

    //Put all plugins targeting framework into list

    if(frameworkPlugs != null) 
    {
        frameworkPlugs.ForEach(plugin => plugin.Action());
    }
}

If it helps knowing what the different variables are here is the entire PluginLoader class

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.IO;
using System.Reflection;
using System.Threading.Tasks;

namespace CSV_Analyzer_Pro.Core.PluginSystem {
    public class PluginLoader {
        public static List<IPlugin> Plugins { set; get; }

        public void LoadPlugins() {
            Plugins = new List<IPlugin>();

            if (Directory.Exists(Constants.PluginFolder)) {
                string[] files = Directory.GetFiles(Constants.PluginFolder);
                foreach(string file in files) {
                    if (file.EndsWith(".dll")) {
                        Assembly.LoadFile(Path.GetFullPath(file));
                    }
                }
            }

            Type interfaceType = typeof(IPlugin);

            Type[] types = AppDomain.CurrentDomain.GetAssemblies().SelectMany(a => a.GetTypes()).Where(p => interfaceType.IsAssignableFrom(p) && p.IsClass).ToArray();

            foreach(Type type in types) {
                Plugins.Add((IPlugin)Activator.CreateInstance(type));
            }
        }

        public void Init() {
            if(Plugins != null) {
                Plugins.ForEach(plugin => plugin.Action());
            }
        }

        public void GetPluginByTargetFramework(string framework) {
            //Get all plugins
            List<IPlugin> frameworkPlugs = new List<IPlugin>();

            //Put all plugins targeting framework into list

            if(frameworkPlugs != null) {
                frameworkPlugs.ForEach(plugin => plugin.Action());
            }
        }
    }
}
Gilad Green
  • 36,708
  • 7
  • 61
  • 95
FlamingGenius
  • 216
  • 3
  • 22
  • So you want only items from `Plugins` that have a certain `framework`? – Gilad Green Sep 17 '17 at 05:36
  • 3
    So, what's your _question_? What is it _specifically_ you are having trouble figuring out? Please fix your question so it includes a good [mcve], along with a detailed and clear explanation of what precisely that code does now and what you want it to do instead, and an explanation of what _specific_ issue you can't solve. – Peter Duniho Sep 17 '17 at 05:38

2 Answers2

1

Use linq's .Where:

frameworkPlugs = Plugins.Where(p => p.TargetFramework == framework);

Putting it all together you can:

public void GetPluginByTargetFramework(string framework) 
{
    Plugins.Where(p => p.TargetFramework == framework)
           .ToList().ForEach(p => p.Action());


    //Better to use a foreach loop on the items returned from the where
    foreach(var item in Plugins.Where(p => p.TargetFramework == framework)
           item.Action();
}

Notice that there is no need to check that collection is not null because linq queries return an IEnumerable<T> which will never be null - if nothing matched the where it will be empty, but not null.

If you want to compare strings case insensitive then have a look at: linq case insensitive (without toUpper or toLower)

Gilad Green
  • 36,708
  • 7
  • 61
  • 95
  • This will not compile. Also, using `ToList` and `ForEach` a waste of time and memory. – Richard Schneider Sep 17 '17 at 07:24
  • @RichardSchneider - for the compilation - true - was a copy paste mistake. For the `ToList` I agree, will add explanation - just decided to stay with the the way OP did – Gilad Green Sep 17 '17 at 08:21
  • This works but creates a `"Error Creating Window Handle"` exception when exiting the application using `Enviroment.Exit (1)` – FlamingGenius Sep 18 '17 at 03:37
  • @FlamingGenius - that is an exception not related to the code above or the specific question. Unfortunately the way to go in SO with followup question is to post a new question for them. Try and solve it and if you still have a problem you can post a new question explaining the problem and I'll be happy to help :) – Gilad Green Sep 18 '17 at 05:20
  • I don't think it started happening till I added this to the application Google searches say it's an issue where too many objects are created? – FlamingGenius Sep 18 '17 at 13:02
  • @FlamingGenius - see edit for explanation about the foreach option – Gilad Green Sep 18 '17 at 18:41
1

You need to filter the list of plugins; Use the Where method.

public void GetPluginByTargetFramework(string framework) 
{
   if (Plugins == null) return;
   foreach (var p in Plugins.Where(p => p.TargetFramework == framework))
     p.Action();
}

BTW, the name doesn't match it operation. Suggest changing to InitForFramework.

Richard Schneider
  • 34,944
  • 9
  • 57
  • 73