-
Notifications
You must be signed in to change notification settings - Fork 0
/
TypeFinder.cs
61 lines (56 loc) · 2.59 KB
/
TypeFinder.cs
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
using System;
using System.Collections.Generic;
using System.Diagnostics.Contracts;
using System.Reflection;
namespace CPlugin.Net;
/// <summary>
/// Represents a type finder for plugins loaded by <see cref="PluginLoader"/>.
/// </summary>
public static class TypeFinder
{
/// <summary>
/// Finds subtypes that implement the contract specified by <typeparamref name="TSupertype"/>
/// using the assemblies loaded by <see cref="PluginLoader"/>.
/// </summary>
/// <typeparam name="TSupertype">
/// The type of contract (base type) shared between the host application and the plugins.
/// </typeparam>
/// <remarks>
/// This method uses the <see cref="PluginAttribute"/> type to create an instance of the subtype, so plugins must use it.
/// </remarks>
/// <returns>
/// An instance of type <see cref="IEnumerable{TSuperType}"/> that allows iterating over the instances
/// that implement the contract specified by <typeparamref name="TSupertype"/>.
/// <para>or</para>
/// Returns an empty enumerable if the <typeparamref name="TSupertype"/> does not have any subtype,
/// or if no assembly uses <see cref="PluginAttribute"/>.
/// <para>This method never returns <c>null</c>.</para>
/// </returns>
public static IEnumerable<TSupertype> FindSubtypesOf<TSupertype>() where TSupertype : class
=> FindSubtypesOf<TSupertype>(PluginLoader.Assemblies);
// This method is only to be used for testing.
// This way you don't have to depend on the plugin loader when testing.
internal static IEnumerable<TSupertype> FindSubtypesOf<TSupertype>(IEnumerable<Assembly> assemblies)
where TSupertype : class
{
if (assemblies is null)
throw new ArgumentNullException(nameof(assemblies));
return GetSubtypesOf<TSupertype>(assemblies);
}
// The logic of this method needs to be separate to ensure
// that the validations of FindSubtypesOf are executed immediately.
private static IEnumerable<TSupertype> GetSubtypesOf<TSupertype>(IEnumerable<Assembly> assemblies)
where TSupertype : class
{
foreach (Assembly assembly in assemblies)
{
var pluginAttributes = assembly.GetCustomAttributes<PluginAttribute>();
foreach (PluginAttribute pluginAttribute in pluginAttributes)
{
Type implementationType = pluginAttribute.PluginType;
if (typeof(TSupertype).IsAssignableFrom(implementationType))
yield return (TSupertype)Activator.CreateInstance(implementationType);
}
}
}
}