[Untested] Assembly Crawler will now accept constructors matching: new(), new(CommandService), new(IDependencyMap). Add IDependencyMap Add DependencyMaptags/1.0-rc
@@ -164,7 +164,7 @@ namespace Discord.Commands | |||||
return loadedModule; | return loadedModule; | ||||
} | } | ||||
public async Task<IEnumerable<Module>> LoadAssembly(Assembly assembly) | |||||
public async Task<IEnumerable<Module>> LoadAssembly(Assembly assembly, IDependencyMap dependencyMap = null) | |||||
{ | { | ||||
var modules = ImmutableArray.CreateBuilder<Module>(); | var modules = ImmutableArray.CreateBuilder<Module>(); | ||||
await _moduleLock.WaitAsync().ConfigureAwait(false); | await _moduleLock.WaitAsync().ConfigureAwait(false); | ||||
@@ -176,7 +176,7 @@ namespace Discord.Commands | |||||
var moduleAttr = typeInfo.GetCustomAttribute<ModuleAttribute>(); | var moduleAttr = typeInfo.GetCustomAttribute<ModuleAttribute>(); | ||||
if (moduleAttr != null && moduleAttr.Autoload) | if (moduleAttr != null && moduleAttr.Autoload) | ||||
{ | { | ||||
var moduleInstance = ReflectionUtils.CreateObject(typeInfo); | |||||
var moduleInstance = ReflectionUtils.CreateObject(typeInfo, this, dependencyMap); | |||||
modules.Add(LoadInternal(moduleInstance, moduleAttr, typeInfo)); | modules.Add(LoadInternal(moduleInstance, moduleAttr, typeInfo)); | ||||
} | } | ||||
} | } | ||||
@@ -0,0 +1,27 @@ | |||||
using System; | |||||
using System.Collections.Generic; | |||||
using System.Reflection; | |||||
namespace Discord.Commands | |||||
{ | |||||
public class DependencyMap : IDependencyMap | |||||
{ | |||||
private Dictionary<Type, object> map; | |||||
public T Get<T>() 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>(T obj) | |||||
{ | |||||
var t = typeof(T); | |||||
if (map.ContainsKey(t)) | |||||
throw new InvalidOperationException($"The dependency map already contains \"{t.FullName}\""); | |||||
map.Add(t, obj); | |||||
} | |||||
} | |||||
} |
@@ -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<T>() where T : class; | |||||
void Add<T>(T obj); | |||||
} | |||||
} |
@@ -43,7 +43,7 @@ namespace Discord.Commands | |||||
nextGroupPrefix = groupPrefix + groupAttrib.Prefix ?? type.Name; | nextGroupPrefix = groupPrefix + groupAttrib.Prefix ?? type.Name; | ||||
else | else | ||||
nextGroupPrefix = groupPrefix; | nextGroupPrefix = groupPrefix; | ||||
SearchClass(ReflectionUtils.CreateObject(type), commands, type, nextGroupPrefix); | |||||
SearchClass(ReflectionUtils.CreateObject(type, Service), commands, type, nextGroupPrefix); | |||||
} | } | ||||
} | } | ||||
} | } | ||||
@@ -6,18 +6,33 @@ namespace Discord.Commands | |||||
{ | { | ||||
internal class ReflectionUtils | 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 | 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}\""); | |||||
} | } | ||||
} | } | ||||
} | } | ||||