jeudi 8 juin 2023

Instantiating unknown generic type with unknown generic parameter

I am trying to build a plugin engine. The only requirement is that a plugin must implement two types: ISettings and IPlugin from the contract.cs below. A basic implementation of a plugin can be found in plugin.cs.

The main application will scan for assemblies implementing these types, creates instances of them and calls the standard Start() method.

It works fine, but I am missing any compile time check because I cannot correctly cast the instances to the desired types in main.cs (I know nothing about plugin.cs in the main app), that's why I am using dynamic.

The main reason for using a generic type is to give access to implementor of plugin.cs to his TSettings type. I could use IPlugin<ISettings> instead but this will oblige the implementor to write Start(ISettings settings) which makes TSettings unusable without a cast.

Another approach was to follow the official IOptions<TSettings> pattern, but the settings object cannot be injected into constructor because settings are built or modified after object creation.

I there any better way to design the contract or to obtain a strong typed reference in main.cs instead of dynamic?

Please note that this is a stripped down example to illustrate the principle, in reality the plugin interface is more complex, TSettings is used in more places and I am using dependency injection instead of the classic Activator.

contract.cs

interface ISettings {}

interface IPlugin<TSettings> where TSettings: ISettings
{
  void Start(TSettings settings);
}

plugin.cs

class SomeSettings: ISettings {}
class SomePlugin<SomeSettings> : IPlugin<SomeSettings>
{
  void Start(SomeSettings settings) { }
}

main.cs

void Load()
{
  Type settingsType = ... // extract settings type from plugin.dll
  Type pluginType = ... // extract plugin type from plugin.dll

  dynamic settings = Activator.CreateInstance(settingsType);
  //all I know is that settings can be cast to ISettings
  dynamic plugin = Activator.CreateInstance(pluginType)
  //all I know is that plugin can be cast to IPlugin<UnknownSettings>

  plugin.Start(settings)
  //it works but plugin being dynamic, I can write anything here.
}








Aucun commentaire:

Enregistrer un commentaire