diff --git a/src/Discord.Net.Commands/Attributes/ModuleAttribute.cs b/src/Discord.Net.Commands/Attributes/ModuleAttribute.cs index 57f525389..ec04041e8 100644 --- a/src/Discord.Net.Commands/Attributes/ModuleAttribute.cs +++ b/src/Discord.Net.Commands/Attributes/ModuleAttribute.cs @@ -6,16 +6,16 @@ namespace Discord.Commands public class ModuleAttribute : Attribute { public string Prefix { get; } - public bool Autoload { get; } - public ModuleAttribute(bool autoload = true) + public bool AutoLoad { get; set; } + public ModuleAttribute() { Prefix = null; - Autoload = autoload; + AutoLoad = true; } - public ModuleAttribute(string prefix, bool autoload = true) + public ModuleAttribute(string prefix) { Prefix = prefix; - Autoload = autoload; + AutoLoad = true; } } } diff --git a/src/Discord.Net.Commands/CommandService.cs b/src/Discord.Net.Commands/CommandService.cs index d0dfeaeb9..46c5aaa39 100644 --- a/src/Discord.Net.Commands/CommandService.cs +++ b/src/Discord.Net.Commands/CommandService.cs @@ -174,7 +174,7 @@ namespace Discord.Commands { var typeInfo = type.GetTypeInfo(); var moduleAttr = typeInfo.GetCustomAttribute(); - if (moduleAttr != null && moduleAttr.Autoload) + if (moduleAttr != null && moduleAttr.AutoLoad) { 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 index 4495a906b..db4d20984 100644 --- a/src/Discord.Net.Commands/Dependencies/DependencyMap.cs +++ b/src/Discord.Net.Commands/Dependencies/DependencyMap.cs @@ -13,12 +13,16 @@ namespace Discord.Commands map = new Dictionary(); } - public T Get() where T : class + public object Get(Type t) { - var t = typeof(T); if (!map.ContainsKey(t)) throw new KeyNotFoundException($"The dependency map does not contain \"{t.FullName}\""); - return map[t] as T; + return map[t]; + } + + public T Get() where T : class + { + return Get(typeof(T)) as T; } public void Add(T obj) diff --git a/src/Discord.Net.Commands/Dependencies/IDependencyMap.cs b/src/Discord.Net.Commands/Dependencies/IDependencyMap.cs index fb2710795..859cff09b 100644 --- a/src/Discord.Net.Commands/Dependencies/IDependencyMap.cs +++ b/src/Discord.Net.Commands/Dependencies/IDependencyMap.cs @@ -7,6 +7,7 @@ namespace Discord.Commands { public interface IDependencyMap { + object Get(Type t); T Get() where T : class; void Add(T obj); } diff --git a/src/Discord.Net.Commands/ReflectionUtils.cs b/src/Discord.Net.Commands/ReflectionUtils.cs index d1eeccb4c..4603563d8 100644 --- a/src/Discord.Net.Commands/ReflectionUtils.cs +++ b/src/Discord.Net.Commands/ReflectionUtils.cs @@ -1,4 +1,5 @@ using System; +using System.Collections.Generic; using System.Linq; using System.Reflection; @@ -6,33 +7,39 @@ namespace Discord.Commands { internal class ReflectionUtils { - internal static object CreateObject(TypeInfo typeInfo, CommandService commands, IDependencyMap map = null) + internal static object CreateObject(TypeInfo typeInfo, CommandService service, IDependencyMap map = null) { if (typeInfo.DeclaredConstructors.Count() > 1) throw new InvalidOperationException($"Found too many constructors for \"{typeInfo.FullName}\""); + var constructor = typeInfo.DeclaredConstructors.FirstOrDefault(); + + if (constructor == null) + throw new InvalidOperationException($"Found no constructor for \"{typeInfo.FullName}\""); + + object[] parameters; + try + { + // TODO: probably change this ternary into something sensible + parameters = constructor.GetParameters() + .Select(x => x.ParameterType == typeof(CommandService) ? service : map.Get(x.ParameterType)).ToArray(); + } + catch (KeyNotFoundException ex) // tried to inject an invalid dependency + { + throw new InvalidOperationException($"Could not find a valid constructor for \"{typeInfo.FullName}\" (could not provide parameter)", ex); + } + catch (NullReferenceException ex) // tried to find a dependency + { + throw new InvalidOperationException($"Could not find a valid constructor for \"{typeInfo.FullName}\" (type requires dependency injection)", ex); + } + try { - 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}\" (Found too many parameters)"); - var parameter = constructor.GetParameters().FirstOrDefault(); - if (parameter == null) - throw new InvalidOperationException($"Could not find a valid constructor for \"{typeInfo.FullName}\" (No valid parameters)"); - if (parameter.ParameterType == typeof(CommandService)) - return constructor.Invoke(new object[1] { commands }); - else if (parameter.ParameterType == typeof(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}\" (Invalid Parameter Type: \"{parameter.ParameterType.FullName}\")"); + return constructor.Invoke(parameters); } - catch (Exception e) + catch (Exception ex) { - throw new InvalidOperationException($"Could not find a valid constructor for \"{typeInfo.FullName}\" (Error invoking constructor)"); + throw new InvalidOperationException($"Could not find a valid constructor for \"{typeInfo.FullName}\" (Error invoking constructor)", ex); } } }