Skip to content

Delegate Plugin Catalog

Mikael Koskinen edited this page Aug 10, 2020 · 4 revisions

Delegate Plugin Catalog is part of the Plugin Framework's main package:

NuGet Version

Delegate Plugin Catalog allows you to use a System.Func or a System.Action as a plugin. Here's a simple example of creating a plugin using an Action:

var catalog = new DelegatePluginCatalog(new Action(() =>
{
    Console.WriteLine("Hello from plugin");
}));

await catalog.Initialize();

Here's an example of a Func-based plugin:

var catalog = new DelegatePluginCatalog(new Func<int, Task<bool>>(async i =>
{
    await Task.Delay(TimeSpan.FromMilliseconds(100));
    Console.WriteLine("Hello from plugin");

    return true;
}));

Here's an example code where a plugin catalog is created and initialized and then a plugin instance is created and executed:

var catalog = new DelegatePluginCatalog(new Action(() =>
{
    Console.WriteLine("Hello from plugin");
}));

await catalog.Initialize();

var ourPlugin = catalog.Single();

dynamic instance = Activator.CreateInstance(ourPlugin);
instance.Run();

Under the hood

Under the hood the DelegatePluginCatalog creates a wrapper class for the delegate. Developer can control the name of the class and its namespace. The generated class contains a single Run-method which can be used to execute the delegate. Method's name can be also changed.

The Run-method's signature matches the delegate's signature. If you have a Func which takes int and bool as parameters and returns a string, the generated method will look like the following:

public string Run(int x, bool y)
{
    ...
    return "result";
}

Options

DelegatePluginCatalogOptions contains a list of conversion rules which can be used to alter the code generation. These rules can do two things:

  • Convert delegate parameters to constructor parameters
  • Convert delegate parameters to properties

By default the generated type doesn't have any constructor parameters nor properties. Given the following example delegate from the sample:

var funcWithExternalService = new Func<string, ExternalService, string>((s, service) =>
{
    var words = service.GetWords();

    s = s + Environment.NewLine + words;

    return s;
});

By default the generated output looks like the following:

public class GeneratedType
{
	public string Run(string s, ExternalService service)
	{
		...
	}
}

The following conversion rules move all the parameters of type ExternalService as constructor parameters and all the parameters named "s" as public properties:

new DelegateConversionRule(info => info.ParameterType == typeof(ExternalService), nfo => new ParameterConversion() { ToConstructor = true }),
new DelegateConversionRule(info => info.Name == "s", nfo => new ParameterConversion() { ToPublicProperty = true }),

Making the generated output like the following:

public class GeneratedType
{
	private ExternalService _service;
	public string S { get;set; }

	public GeneratedType(ExternalService service)
	{
		_service = service;
	}
	
	public string Run()
	{
		...
	}
}