Improve DI system
This commit is contained in:
@@ -6,16 +6,16 @@ namespace Discord.Commands
|
|||||||
public class ModuleAttribute : Attribute
|
public class ModuleAttribute : Attribute
|
||||||
{
|
{
|
||||||
public string Prefix { get; }
|
public string Prefix { get; }
|
||||||
public bool Autoload { get; }
|
public bool AutoLoad { get; set; }
|
||||||
public ModuleAttribute(bool autoload = true)
|
public ModuleAttribute()
|
||||||
{
|
{
|
||||||
Prefix = null;
|
Prefix = null;
|
||||||
Autoload = autoload;
|
AutoLoad = true;
|
||||||
}
|
}
|
||||||
public ModuleAttribute(string prefix, bool autoload = true)
|
public ModuleAttribute(string prefix)
|
||||||
{
|
{
|
||||||
Prefix = prefix;
|
Prefix = prefix;
|
||||||
Autoload = autoload;
|
AutoLoad = true;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -174,7 +174,7 @@ namespace Discord.Commands
|
|||||||
{
|
{
|
||||||
var typeInfo = type.GetTypeInfo();
|
var typeInfo = type.GetTypeInfo();
|
||||||
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, this, dependencyMap);
|
var moduleInstance = ReflectionUtils.CreateObject(typeInfo, this, dependencyMap);
|
||||||
modules.Add(LoadInternal(moduleInstance, moduleAttr, typeInfo));
|
modules.Add(LoadInternal(moduleInstance, moduleAttr, typeInfo));
|
||||||
|
|||||||
@@ -13,12 +13,16 @@ namespace Discord.Commands
|
|||||||
map = new Dictionary<Type, object>();
|
map = new Dictionary<Type, object>();
|
||||||
}
|
}
|
||||||
|
|
||||||
public T Get<T>() where T : class
|
public object Get(Type t)
|
||||||
{
|
{
|
||||||
var t = typeof(T);
|
|
||||||
if (!map.ContainsKey(t))
|
if (!map.ContainsKey(t))
|
||||||
throw new KeyNotFoundException($"The dependency map does not contain \"{t.FullName}\"");
|
throw new KeyNotFoundException($"The dependency map does not contain \"{t.FullName}\"");
|
||||||
return map[t] as T;
|
return map[t];
|
||||||
|
}
|
||||||
|
|
||||||
|
public T Get<T>() where T : class
|
||||||
|
{
|
||||||
|
return Get(typeof(T)) as T;
|
||||||
}
|
}
|
||||||
|
|
||||||
public void Add<T>(T obj)
|
public void Add<T>(T obj)
|
||||||
|
|||||||
@@ -7,6 +7,7 @@ namespace Discord.Commands
|
|||||||
{
|
{
|
||||||
public interface IDependencyMap
|
public interface IDependencyMap
|
||||||
{
|
{
|
||||||
|
object Get(Type t);
|
||||||
T Get<T>() where T : class;
|
T Get<T>() where T : class;
|
||||||
void Add<T>(T obj);
|
void Add<T>(T obj);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,4 +1,5 @@
|
|||||||
using System;
|
using System;
|
||||||
|
using System.Collections.Generic;
|
||||||
using System.Linq;
|
using System.Linq;
|
||||||
using System.Reflection;
|
using System.Reflection;
|
||||||
|
|
||||||
@@ -6,33 +7,39 @@ namespace Discord.Commands
|
|||||||
{
|
{
|
||||||
internal class ReflectionUtils
|
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)
|
if (typeInfo.DeclaredConstructors.Count() > 1)
|
||||||
throw new InvalidOperationException($"Found too many constructors for \"{typeInfo.FullName}\"");
|
throw new InvalidOperationException($"Found too many constructors for \"{typeInfo.FullName}\"");
|
||||||
|
|
||||||
var constructor = typeInfo.DeclaredConstructors.FirstOrDefault();
|
var constructor = typeInfo.DeclaredConstructors.FirstOrDefault();
|
||||||
|
|
||||||
|
if (constructor == null)
|
||||||
|
throw new InvalidOperationException($"Found no constructor for \"{typeInfo.FullName}\"");
|
||||||
|
|
||||||
|
object[] parameters;
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
if (constructor.GetParameters().Length == 0)
|
// TODO: probably change this ternary into something sensible
|
||||||
return constructor.Invoke(null);
|
parameters = constructor.GetParameters()
|
||||||
else if (constructor.GetParameters().Length > 1)
|
.Select(x => x.ParameterType == typeof(CommandService) ? service : map.Get(x.ParameterType)).ToArray();
|
||||||
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}\")");
|
|
||||||
}
|
}
|
||||||
catch (Exception e)
|
catch (KeyNotFoundException ex) // tried to inject an invalid dependency
|
||||||
{
|
{
|
||||||
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}\" (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
|
||||||
|
{
|
||||||
|
return constructor.Invoke(parameters);
|
||||||
|
}
|
||||||
|
catch (Exception ex)
|
||||||
|
{
|
||||||
|
throw new InvalidOperationException($"Could not find a valid constructor for \"{typeInfo.FullName}\" (Error invoking constructor)", ex);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user