From bbe51012cf91fd81a50c894971ad5244bfa308ef Mon Sep 17 00:00:00 2001 From: Christopher F Date: Wed, 20 Jul 2016 17:50:52 -0400 Subject: [PATCH] Add Dependency Map, Update Assembly Crawler [Untested] Assembly Crawler will now accept constructors matching: new(), new(CommandService), new(IDependencyMap). Add IDependencyMap Add DependencyMap --- src/Discord.Net.Commands/CommandService.cs | 4 +-- .../Dependencies/DependencyMap.cs | 27 +++++++++++++++++ .../Dependencies/IDependencyMap.cs | 13 +++++++++ src/Discord.Net.Commands/Module.cs | 2 +- src/Discord.Net.Commands/ReflectionUtils.cs | 29 ++++++++++++++----- 5 files changed, 65 insertions(+), 10 deletions(-) create mode 100644 src/Discord.Net.Commands/Dependencies/DependencyMap.cs create mode 100644 src/Discord.Net.Commands/Dependencies/IDependencyMap.cs diff --git a/src/Discord.Net.Commands/CommandService.cs b/src/Discord.Net.Commands/CommandService.cs index 9fd8aecc9..d0dfeaeb9 100644 --- a/src/Discord.Net.Commands/CommandService.cs +++ b/src/Discord.Net.Commands/CommandService.cs @@ -164,7 +164,7 @@ namespace Discord.Commands return loadedModule; } - public async Task> LoadAssembly(Assembly assembly) + public async Task> LoadAssembly(Assembly assembly, IDependencyMap dependencyMap = null) { var modules = ImmutableArray.CreateBuilder(); await _moduleLock.WaitAsync().ConfigureAwait(false); @@ -176,7 +176,7 @@ namespace Discord.Commands var moduleAttr = typeInfo.GetCustomAttribute(); if (moduleAttr != null && moduleAttr.Autoload) { - var moduleInstance = ReflectionUtils.CreateObject(typeInfo); + var moduleInstance = ReflectionUtils.CreateObject(typeInfo, this, dependencyMap); modules.Add(LoadInternal(moduleInstance, moduleAttr, typeInfo)); } } diff --git a/src/Discord.Net.Commands/Dependencies/DependencyMap.cs b/src/Discord.Net.Commands/Dependencies/DependencyMap.cs new file mode 100644 index 000000000..20d9a60c5 --- /dev/null +++ b/src/Discord.Net.Commands/Dependencies/DependencyMap.cs @@ -0,0 +1,27 @@ +using System; +using System.Collections.Generic; +using System.Reflection; + +namespace Discord.Commands +{ + public class DependencyMap : IDependencyMap + { + private Dictionary map; + + public T Get() where T : class + { + var t = typeof(T); + if (!map.ContainsKey(t)) + throw new KeyNotFoundException($"The dependency map does not contain \"{t.FullName}\""); + return map[t] as T; + } + + public void Add(T obj) + { + var t = typeof(T); + if (map.ContainsKey(t)) + throw new InvalidOperationException($"The dependency map already contains \"{t.FullName}\""); + map.Add(t, obj); + } + } +} diff --git a/src/Discord.Net.Commands/Dependencies/IDependencyMap.cs b/src/Discord.Net.Commands/Dependencies/IDependencyMap.cs new file mode 100644 index 000000000..fb2710795 --- /dev/null +++ b/src/Discord.Net.Commands/Dependencies/IDependencyMap.cs @@ -0,0 +1,13 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Threading.Tasks; + +namespace Discord.Commands +{ + public interface IDependencyMap + { + T Get() where T : class; + void Add(T obj); + } +} diff --git a/src/Discord.Net.Commands/Module.cs b/src/Discord.Net.Commands/Module.cs index ea6e29c28..b884832bc 100644 --- a/src/Discord.Net.Commands/Module.cs +++ b/src/Discord.Net.Commands/Module.cs @@ -43,7 +43,7 @@ namespace Discord.Commands nextGroupPrefix = groupPrefix + groupAttrib.Prefix ?? type.Name; else nextGroupPrefix = groupPrefix; - SearchClass(ReflectionUtils.CreateObject(type), commands, type, nextGroupPrefix); + SearchClass(ReflectionUtils.CreateObject(type, Service), commands, type, nextGroupPrefix); } } } diff --git a/src/Discord.Net.Commands/ReflectionUtils.cs b/src/Discord.Net.Commands/ReflectionUtils.cs index 28672a06f..98f1989be 100644 --- a/src/Discord.Net.Commands/ReflectionUtils.cs +++ b/src/Discord.Net.Commands/ReflectionUtils.cs @@ -6,18 +6,33 @@ namespace Discord.Commands { internal class ReflectionUtils { - internal static object CreateObject(TypeInfo typeInfo) + internal static object CreateObject(TypeInfo typeInfo, CommandService commands, IDependencyMap map = null) { - var constructor = typeInfo.DeclaredConstructors.Where(x => x.GetParameters().Length == 0).FirstOrDefault(); - if (constructor == null) - throw new InvalidOperationException($"Failed to find a valid constructor for \"{typeInfo.FullName}\""); + if (typeInfo.DeclaredConstructors.Count() > 1) + throw new InvalidOperationException($"Found too many constructors for \"{typeInfo.FullName}\""); + var constructor = typeInfo.DeclaredConstructors.FirstOrDefault(); try { - return constructor.Invoke(null); + if (constructor.GetParameters().Length == 0) + return constructor.Invoke(null); + else if (constructor.GetParameters().Length > 1) + throw new InvalidOperationException($"Could not find a valid constructor for \"{typeInfo.FullName}\""); + var parameter = constructor.GetParameters().FirstOrDefault(); + if (parameter == null) + throw new InvalidOperationException($"Could not find a valid constructor for \"{typeInfo.FullName}\""); + if (parameter.GetType() == typeof(CommandService)) + return constructor.Invoke(new object[1] { commands }); + else if (parameter is IDependencyMap) + { + if (map == null) throw new InvalidOperationException($"The constructor for \"{typeInfo.FullName}\" requires a Dependency Map."); + return constructor.Invoke(new object[1] { map }); + } + else + throw new InvalidOperationException($"Could not find a valid constructor for \"{typeInfo.FullName}\""); } - catch (Exception ex) + catch { - throw new InvalidOperationException($"Failed to create \"{typeInfo.FullName}\"", ex); + throw new InvalidOperationException($"Could not find a valid constructor for \"{typeInfo.FullName}\""); } } }