2

Is there a way to force a static method to be executed in system initialization?

I'm developing a system all based in plugins. The core of the project will contain the system's state and will fire some events where plugins can hook up and create new features.

I want this plugin mechanism to be done transparently from plugins. All the plugin must do is implement an event of the system core and it should be executed correctly. The problem is for do that I need to execute some code on each plugin to hook the system core events. The solution I first thought was to declare some method in these plugins that will be executed when the assembly is loaded or something like that, but apparently static constructors are only executed when some reference of any of his fields is made; but in my design it can't be done: the plugins must stay invisible for the system core.

The plugins are essentially other classes or other projects.

Any thoughts?

Thanks.

andresantacruz
  • 1,676
  • 10
  • 17
  • Can the plugin host enumerate all loaded assemblies on startup and look for types implementing an initialization interface that you define? – Michael Liu Apr 23 '16 at 18:36
  • I'd design my plugin architecture such that every plugin needs to implement an `Initialize()` method. Then when your application is starting up you just loop through all the plugins you find and explicitly call that method on each one. Better to have explicit initialization process that you drive rather than leave it up to your plugins (which could break something in the process) – p.s.w.g Apr 23 '16 at 18:37
  • Yes, although it is not the best scenrious. It would be awesome if the plugins could just be classes implemented in a given assembly (dll). In this design I'm trying to achieve, all the real business rules will be implemented in the plugins, and the project is relatively big, so if I have to create 1 assembly for each plugin I will have a lot of projects inside the solution and I consider this a bad thing. – andresantacruz Apr 23 '16 at 18:39
  • Create a `BasePlugin` class and have all your plugins inherit it. Have an `Init` in this method which does your shared logic (or do it in constructor). Then in your plugin you can use `base.Init()` or do it in the constructor – Arijoon Apr 23 '16 at 18:40
  • Hello @Arijoon! Doing that I should explicity call these Init methods, shouldnt I? This is exactly what I'm trying to avoid. I want the initialization process of the plugins to be executed automatically, without the need to explicity call these initialization methods. – andresantacruz Apr 23 '16 at 18:43
  • Hey @p.s.w.g! How do you imagine I could do that without explicit calling these Initialize() methods? – andresantacruz Apr 23 '16 at 18:44
  • Not if it's in the constructor. Then when your plugin class is being initialized ( it's constructor will be called) then the init logic will also be called because it is in the parent's constructor. I highly advise against automically calling these. An explicit call to the parent's Init is much better than having it automatically called by constructor but that's finally your decision – Arijoon Apr 23 '16 at 18:45
  • @Arijoon But for the constructor to be called, any other executing code must explicit reference a field of our plugins, i.e. let's say I have 200 plugins, imagine how pain would be if I had to explicit initialize all of the plugins. – andresantacruz Apr 23 '16 at 18:48
  • But how are you going to use them if they aren't initialised? Are they static classes? – Arijoon Apr 23 '16 at 18:49
  • How invested are you in using static classes, have you looked into using singletons instead? – gmiley Apr 23 '16 at 18:50
  • @Arijoon. They could be static classes yes. The idea is that these plugins are hooked up in the system transparently. The plugins wouldn't have the need to explicit be initialized, you kow? The simple fact that the plugin classes stays in a specific assembly should be sufficient to be initialized when the system initiates. – andresantacruz Apr 23 '16 at 18:52
  • @gmiley These plugins could be singletons, but how this could help in my case? Thanks. – andresantacruz Apr 23 '16 at 18:53
  • A singleton is a regular class that would have to be initialized, is that not the goal you are trying to achieve? The difference between a singleton and a regular class is that instead of initializing a new instance each time an instance is attempted to be created, it returns a reference to the first instance that was created. In that way it behaves as a static class, but with the benefit of being a fully initialized instance. – gmiley Apr 23 '16 at 18:55
  • Static classes for this type of behaviour are not a good practice. Please look at dependency injection and modify your architecture to register them as dependencies. Then they can be injected into any class that requires them. As @gmiley suggested you can then also register them as singleton dependencies. Look at `Ninject` which is my favorite and it's very simple to use – Arijoon Apr 23 '16 at 18:56
  • I guess I expressed myself badly. Look: the whole point of my design is to separate the system's state from all the code which modifies this state. I will have the process of initializing the system state and in this process, all the plugins (classes in a specific assembly) must be initialized automatically (e.g. use Reflection to get the types of this plugin assembly, check if the types implements a specific interface and call its Init() method - all this done transparently in a simple loop at system initialization). What you guys are suggesting revolves around explicit calling each plugin. – andresantacruz Apr 23 '16 at 19:07
  • With a singleton, or non-static classes in general, you don't have to explicitly call an initializer, you simply create an instance of that class, the constructor does all the work for you. If you really wanted, you don't even need to know the type/name of the class either. Even better is if your plugins are required to implement a base class or interface, which is a very common pattern. If you could, maybe provide a simple example of how you are expecting this to work. – gmiley Apr 23 '16 at 19:30
  • I know @gmiley, the problem is that instantiating a class is exactly what I'm trying to avoid. In my scenarious instantiate a class is the same as calling a static Init() method: I will being referencing the plugins the exact same way and this is what I dont want. – andresantacruz Apr 23 '16 at 19:35
  • A example of how I imagine this working: I have a class called CSystemState, this class will contain all the state of the system and will fire some events - lets say one of those events is when the user inputs some data. I will have, in the other hand, a plugin implementing that event and executing the code related to that event and therefore modifying the CSystemState. The problem of having to explicit initializing each of the plugins is that my project will end up of thousands of plugins. Imagine how bad it would be to initialize each one of them! – andresantacruz Apr 23 '16 at 19:37
  • Take a look at [Managed Extensibility](https://msdn.microsoft.com/en-us/library/dd460648(v=vs.110).aspx) and [Add-ins Framework](https://msdn.microsoft.com/en-us/library/bb384200(v=vs.110).aspx). You don't need to re-invent the wheel. – p.s.w.g Apr 23 '16 at 21:37

1 Answers1

1

I think the simplest thing to do is to define a common name for this method (like init()) and call it after you load each library.

Update, as said in comments

The point is to have a common, well defined, structure for the plugins, so which one you're loading at any given point does not matter, they're all the same from the core's point of view. It can just do something like

PluginType instantiatedPlugin=methodThatInstantiates(pluginClass);
instantiatedPlugin.init();

Then you can just loop through a list of plugins massively instantiating and initialising all of them.

If each plugin is a separated DLL, the list can be all the *.dll files in a plugins directory (add some security validation).

Or you could use Reflection to fetch all the plugins' classes. This is valid if the classes are inside the same binary or also after you loaded all DLLs.

You could do it easily if all the plugins are under the same namespace. See: Getting all types in a namespace via reflection

Community
  • 1
  • 1
Gabriel
  • 2,170
  • 1
  • 17
  • 20
  • This is the approach I'm using actually, but it takes a lot of scalability of the design. The ideal should be the plugins being initialized automatically be the system core. – andresantacruz Apr 23 '16 at 18:41
  • Maybe it's not working for you because of how you've designed it. You could have a base class for your plugins and then you massively load them from a list of plugins. With one loop and two lines you loaded all plugins and called all init() methods. – Gabriel Apr 23 '16 at 19:05
  • Yes, but I will have a enormous list declaring the plugins. This creates the dependency between the plugins and the system state that I don't want. – andresantacruz Apr 23 '16 at 19:09
  • Where are you storing this plugins? Sepparated DLLS? The point is to have a common, well defined, structure for the plugins, so which one you're loading at any given point does not matter, they're all the same from the core's point of view. Maybe the list of plugins to load can be the *.dll files in a plugins directory? Or use reflection to fetch the classes? Or something like that. You should post some code otherwise. – Gabriel Apr 23 '16 at 19:37
  • I will give a try to Reflection! I'm reading some articles about it to make some tests. The problem in the Reflection I'm afraid is the overhead on enumerating all the plugin classes. If static constructors were executed always at process initialization for example, I would not have this problem: all I should do is implement the plugins as static classes and put the hook-up code in the static constructor; but static constructors are only executed when a first reference of the class is made - and I don't want that to happen. – andresantacruz Apr 23 '16 at 19:41
  • 1
    I understand, but I don't think you are going to find something else. IMHO any solution would do the same internally. Better to build your own method as light as possible. Static constructors are called when the class is first used (property used or method called). That's their only behaviour. Static constructors don't even exist in most languages. With reflection, you could easily query all plugins if you have all of them under the same namespace. – Gabriel Apr 23 '16 at 19:51
  • I'll do this then! Thank you very much @Gabriel. If you edit your answer with this solution of using Reflection I will accept as the question's answer. – andresantacruz Apr 23 '16 at 19:54
  • 1
    Done. Thanks to you. – Gabriel Apr 23 '16 at 20:00
  • A suggestion to go along with this, you could define your `Init()` method to accept a `Func<>` or `Action<>` parameter so you can pass in an anonymous code block that would get execute within the scope of the plugin. This could be used to expand the functionality of your plugins/application without the need of either knowing anything more about each other. – gmiley Apr 23 '16 at 20:18