MethodAggregator 2.0.0
See the version list below for details.
dotnet add package MethodAggregator --version 2.0.0
NuGet\Install-Package MethodAggregator -Version 2.0.0
<PackageReference Include="MethodAggregator" Version="2.0.0" />
<PackageVersion Include="MethodAggregator" Version="2.0.0" />
<PackageReference Include="MethodAggregator" />
paket add MethodAggregator --version 2.0.0
#r "nuget: MethodAggregator, 2.0.0"
#:package MethodAggregator@2.0.0
#addin nuget:?package=MethodAggregator&version=2.0.0
#tool nuget:?package=MethodAggregator&version=2.0.0
MethodAggregator
Simplifying Access to Methods in Complex Applications
![]() |
MethodAggregator is a C# library that allows you to manage, register, and execute methods dynamically. It provides functionality to find and execute the most suitable method based on the provided parameters and return type. |
|---|
The idea of the MethodAggregator emerged to simplify access to and invocation of methods from different components in complex applications. In modern software development, there is a constant effort to find efficient and elegant solutions that make the code more readable, maintainable, and flexible. The MethodAggregator contributes to handling a wide range of use cases and scenarios while improving the efficiency and structure of the development process.
In complex applications and interactions between multiple components, organizing method calls and dependencies can be challenging. Modularity and reusability are crucial for avoiding redundancy and maintainability issues. Event handling or messaging systems enable communication between components but are often not ideal and can appear cumbersome when direct method calls are desired.
The MethodAggregator, provides an alternative to an IoC container in certain cases by focusing on organizing and invoking methods rather than managing classes and interfaces. The advantage of the MethodAggregator lies in the targeted organization and handling of methods in selected use cases, the optimization of the application structure and logic, and thus the improvement of code quality.
Registration
The MethodAggregator operates as a centralized structure that manages methods using a registration name and parameters, simplifying method invocation via reflection, hence eliminating concerns about instantiation or order of component registration. Its core functionality includes the Register method, allowing delegate instances registration optionally with a provided name, or by default using the method name when the overload without a name is applied. Post-registration, these methods can be invoked through different Execute methods.
Execution
The Execute method in MethodAggregator first checks for a match via the registration parameter and, when multiple registrations have the same name, it identifies a method with an equivalent or convertible return type. This applies to method parameters passed to Execute as well. The SimpleExecute call, however, does not pre-filter by registration name; instead, it scans the entire method list for an appropriate delegate based on return and input parameters, streamlining the use of the MethodAggregator, particularly when the number of registered methods is low, and straightforward access to a method is desired.
But how does the search for the right method work in detail? For this, the implementation in the FindDelegate method uses three helper methods called in succession.
FilterCountOfParameterMatchesFilterParameterTypesAreAssignableFilterParameterBestTypeMatches
The method FilterCountOfParameterMatches initially filters methods that share the same number of parameters as the provided ones. This is followed by FilterParameterTypesAreAssignable, which filters based on parameter and return types being assignable or convertible to specific types. The final filtration is performed by FilterParameterBestTypeMatches, selecting methods with the highest degree of match with the designated types, considering both native types and classes or interfaces. For the latter, a tree structure of inheritance and implementation levels is created, cached, and used for finding the "most obvious" match. If multiple methods remain post filtration, the first one is chosen; if specificity is required, method registration names should be used. Concurrent execution is prevented through the use of separate lock objects created during method registration, ensuring thread safety in a multithreading context.
The following are various application examples for the MethodAggregator to better illustrate its functionality and versatility.
Application Example 1: Registering Methods and Calling Suppose you have an application that should perform various mathematical operations.
Snippet 1: Methods for performing addition and multiplication
public int Add(int a, int b)
{
return a + b;
}
public int Multiply(int a, double b)
{
return (int)(a * b);
}
Snippet 2: Registering methods
IMethodAggregator aggregator = new MethodAggregator(RegisteringBehaviour.MethodName);
aggregator.Register(Add);
aggregator.Register(Multiply);
Snippet 3: Calling with registration names (by default the same as the method name)
int sum = aggregator.Execute<int>("Add", 3, 5);
int product = aggregator.Execute<int>("Multiply", 3, 5.0);
Snippet 4: Simplified calling (when input and return parameter types are unique)
int sum = aggregator.SimpleExecute<int>(3, 5);
int product = aggregator.SimpleExecute<int>(3, 5.0);
Application Example 2: Using Conversion Logic
As mentioned, the MethodAggregator has complex search algorithms to find the method with the highest probability, even when the given parameter types or the requested return type do not explicitly match. The following example (see Snippet 5 & 6) should illustrate this again.
Snippet 5: Exemplary class and interface schema
class MyClass1 : MyClass2, IMyInterface1
{
public string Bar { get; set; }
}
class MyClass2 : IMyInterface2
{
public string Foo { get; set; }
}
interface IMyInterface1 : IMyInterface2
{
string Bar { get; set; }
}
interface IMyInterface2
{
string Foo { get; set; }
}
Snippet 6: Sample code for testing the behavior
void Action1(MyClass1 obj) => Console.WriteLine("Method1 with MyClass1 was called.");
void Action2(IMyInterface1 obj) => Console.WriteLine("Method2 with IMyInterface1 was called.");
void Action3(MyClass2 obj) => Console.WriteLine("Method3 with MyClass2 was called.");
void Action4(IMyInterface2 obj) => Console.WriteLine("Method4 with IMyInterface2 was called.");
aggregator.Register(Action1);
aggregator.Register(Action2);
aggregator.Register(Action3);
aggregator.Register(Action4);
aggregator.SimpleExecute(new MyClass1());
aggregator.SimpleExecute(new MyClass2());
Table 1: For MyClass1, the following order is obtained | Priority | Type | | -------- | ------------- | | 1 | MyClass1 | | 2 | MyClass2 | | 3 | IMyInterface1 | | 4 | IMyInterface2 |
Table 2: and for MyClass2 | Priority | Type | | -------- | ------------- | | 1 | MyClass2 | | 2 | IMyInterface2 |
Example 3: Use in a plugin architecture Suppose you have an application with a plugin architecture. Plugins can provide their own methods that can be called by the main application. In this case, the MethodAggregator can be used to manage and call methods from different plugins.
Snippet 7: Interface for the plugins
public interface IPlugin
{
string Name { get; }
void RegisterMethods(MethodAggregator aggregator);
}
Snippet 8: The two plugins implementing their useful functions
public class PluginA : IPlugin
{
public string Name => "PluginA";
public void RegisterMethods(MethodAggregator aggregator)
{
aggregator.Register(ToUpper);
}
private string ToUpper(string input)
{
return input.ToUpper();
}
}
public class PluginB : IPlugin
{
public string Name => "PluginB";
public void RegisterMethods(MethodAggregator aggregator)
{
aggregator.Register(Reverse);
}
private string Reverse(string input)
{
return new string(input.Reverse().ToArray());
}
}
Snippet 9: Registering the methods of the plugins in the main application and calling them
List<IPlugin> plugins = new List<IPlugin> { new PluginA(), new PluginB() };
IMethodAggregator aggregator = new MethodAggregator(RegisteringBehaviour.ClassAndMethodName);
foreach (IPlugin plugin in plugins)
{
plugin.RegisterMethods(aggregator);
}
string input = "Hello, world!";
string upper = aggregator.Execute<string>("PluginA.ToUpper", input);
string reversed = aggregator.Execute<string>("PluginB.Reverse", input);
Console.WriteLine($"Input: {input}");
Console.WriteLine($"ToUpper: {upper}");
Console.WriteLine($"Reverse: {reversed}");
// Input: Hello, world!
// ToUpper: HELLO, WORLD!
// Reverse: !dlrow ,olleH
These examples demonstrate how the MethodAggregator can be used to register, manage, and call methods in various scenarios. By using the MethodAggregator, you can make your applications more modular and maintainable while benefiting from a simple and flexible way of calling functions.
Methods
The MethodAggregator class provides the following methods for managing and executing registered methods:
Execute<T>(string name, params object[] parameters): Executes the method with the specified name and parameters, returning a value of type TExecute(string name, params object[] parameters): Executes the method with the specified name and parameters, without returning a valueSimpleExecute<T>(params object[] parameters): Executes the method with the specified parameters, without specifying a name, and returns a value of type TSimpleExecute(params object[] parameters): Executes the method with the specified parameters, without specifying a name or returning a valueTryExecute<T>(out T returnValue, string name, params object[] parameters): Attempts to execute the method with the specified name and parameters, returning a value of type T, and returns a boolean indicating whether the operation succeededTryExecute(string name, params object[] parameters): Attempts to execute the method with the specified name and parameters, without returning a value, and returns a boolean indicating whether the operation succeededIsRegistered(Delegate del): Returns a boolean indicating whether the specified delegate is registered in the aggregatorRegister(Delegate del, string name = null): Registers the specified delegate with the in the constructor specified RegisteringBehaviour or the custom given nameRegister(Delegate del, RegisteringBehavoiur registeringBehaviour, string name = null): Registers the specified delegate with the given name adhering to the specified registering behaviourUnregister(Delegate del): Unregisters the specified delegate from the aggregatorDispose(): Releases all resources used by the MethodAggregator instance
Dependencies
JetBrains.Annotations
License
This project is licensed under the MIT License. See the LICENSE file for details.
| Product | Versions Compatible and additional computed target framework versions. |
|---|---|
| .NET | net5.0 was computed. net5.0-windows was computed. net6.0 was computed. net6.0-android was computed. net6.0-ios was computed. net6.0-maccatalyst was computed. net6.0-macos was computed. net6.0-tvos was computed. net6.0-windows was computed. net7.0 was computed. net7.0-android was computed. net7.0-ios was computed. net7.0-maccatalyst was computed. net7.0-macos was computed. net7.0-tvos was computed. net7.0-windows was computed. net8.0 was computed. net8.0-android was computed. net8.0-browser was computed. net8.0-ios was computed. net8.0-maccatalyst was computed. net8.0-macos was computed. net8.0-tvos was computed. net8.0-windows was computed. net9.0 was computed. net9.0-android was computed. net9.0-browser was computed. net9.0-ios was computed. net9.0-maccatalyst was computed. net9.0-macos was computed. net9.0-tvos was computed. net9.0-windows was computed. net10.0 was computed. net10.0-android was computed. net10.0-browser was computed. net10.0-ios was computed. net10.0-maccatalyst was computed. net10.0-macos was computed. net10.0-tvos was computed. net10.0-windows was computed. |
| .NET Core | netcoreapp2.0 was computed. netcoreapp2.1 was computed. netcoreapp2.2 was computed. netcoreapp3.0 was computed. netcoreapp3.1 was computed. |
| .NET Standard | netstandard2.0 is compatible. netstandard2.1 was computed. |
| .NET Framework | net461 was computed. net462 was computed. net463 was computed. net47 was computed. net471 was computed. net472 was computed. net48 was computed. net481 was computed. |
| MonoAndroid | monoandroid was computed. |
| MonoMac | monomac was computed. |
| MonoTouch | monotouch was computed. |
| Tizen | tizen40 was computed. tizen60 was computed. |
| Xamarin.iOS | xamarinios was computed. |
| Xamarin.Mac | xamarinmac was computed. |
| Xamarin.TVOS | xamarintvos was computed. |
| Xamarin.WatchOS | xamarinwatchos was computed. |
-
.NETStandard 2.0
- JetBrains.Annotations (>= 2022.3.1)
NuGet packages
This package is not used by any NuGet packages.
GitHub repositories
This package is not used by any popular GitHub repositories.
| Version | Downloads | Last Updated | |
|---|---|---|---|
| 2.0.1 | 256 | 9/18/2023 | |
| 2.0.0 | 350 | 5/11/2023 | |
| 1.0.5 | 339 | 5/11/2023 | |
| 1.0.4 | 372 | 5/11/2023 | |
| 1.0.4-ci.19 | 349 | 5/11/2023 | |
| 1.0.4-ci.18 | 359 | 5/4/2023 | |
| 1.0.4-ci.17 | 360 | 5/4/2023 | |
| 1.0.4-ci.16 | 355 | 5/4/2023 | |
| 1.0.4-ci.15 | 363 | 4/13/2023 | |
| 1.0.4-ci.14 | 364 | 4/9/2023 | |
| 1.0.4-ci.13 | 358 | 4/9/2023 | |
| 1.0.4-ci.12 | 358 | 4/9/2023 | |
| 1.0.4-ci.11 | 351 | 4/9/2023 | |
| 1.0.4-ci.10 | 368 | 4/9/2023 | |
| 1.0.4-ci.8 | 356 | 4/9/2023 | |
| 1.0.4-ci.7 | 360 | 4/9/2023 | |
| 1.0.4-ci.6 | 359 | 4/7/2023 | |
| 1.0.4-ci.5 | 371 | 4/5/2023 | |
| 1.0.4-ci.4 | 359 | 4/4/2023 | |
| 1.0.3 | 722 | 4/4/2023 |
