Browse Source

Improve DI system

tags/1.0-rc
Finite Reality 9 years ago
parent
commit
f7455c389b
5 changed files with 40 additions and 28 deletions
  1. +5
    -5
      src/Discord.Net.Commands/Attributes/ModuleAttribute.cs
  2. +1
    -1
      src/Discord.Net.Commands/CommandService.cs
  3. +7
    -3
      src/Discord.Net.Commands/Dependencies/DependencyMap.cs
  4. +1
    -0
      src/Discord.Net.Commands/Dependencies/IDependencyMap.cs
  5. +26
    -19
      src/Discord.Net.Commands/ReflectionUtils.cs

+ 5
- 5
src/Discord.Net.Commands/Attributes/ModuleAttribute.cs View File

@@ -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 ModuleAttribute(bool autoload = true)
public bool AutoLoad { get; set; }
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;
} }
} }
} }

+ 1
- 1
src/Discord.Net.Commands/CommandService.cs View File

@@ -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));


+ 7
- 3
src/Discord.Net.Commands/Dependencies/DependencyMap.cs View File

@@ -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)


+ 1
- 0
src/Discord.Net.Commands/Dependencies/IDependencyMap.cs View File

@@ -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);
} }


+ 26
- 19
src/Discord.Net.Commands/ReflectionUtils.cs View File

@@ -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
{
// 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 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);
} }
} }
} }


Loading…
Cancel
Save