Browse Source

Cleaned up new DependencyMap system

tags/1.0-rc
RogueException 8 years ago
parent
commit
b029725bb1
3 changed files with 57 additions and 61 deletions
  1. +30
    -11
      src/Discord.Net.Commands/Dependencies/DependencyMap.cs
  2. +6
    -5
      src/Discord.Net.Commands/Dependencies/IDependencyMap.cs
  3. +21
    -45
      src/Discord.Net.Commands/ReflectionUtils.cs

+ 30
- 11
src/Discord.Net.Commands/Dependencies/DependencyMap.cs View File

@@ -1,6 +1,5 @@
using System;
using System.Collections.Generic;
using System.Reflection;

namespace Discord.Commands
{
@@ -13,24 +12,44 @@ namespace Discord.Commands
map = new Dictionary<Type, object>();
}

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

public T Get<T>()
{
return (T)Get(typeof(T));
}
public object Get(Type t)
{
if (!map.ContainsKey(t))
object result;
if (!TryGet(t, out result))
throw new KeyNotFoundException($"The dependency map does not contain \"{t.FullName}\"");
return map[t];
else
return result;
}

public T Get<T>() where T : class
public bool TryGet<T>(out T result)
{
return Get(typeof(T)) as T;
object untypedResult;
if (TryGet(typeof(T), out untypedResult))
{
result = (T)untypedResult;
return true;
}
else
{
result = default(T);
return false;
}
}

public void Add<T>(T obj)
public bool TryGet(Type t, out object result)
{
var t = typeof(T);
if (map.ContainsKey(t))
throw new InvalidOperationException($"The dependency map already contains \"{t.FullName}\"");
map.Add(t, obj);
return map.TryGetValue(t, out result);
}
}
}

+ 6
- 5
src/Discord.Net.Commands/Dependencies/IDependencyMap.cs View File

@@ -1,14 +1,15 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Threading.Tasks;

namespace Discord.Commands
{
public interface IDependencyMap
{
object Get(Type t);
T Get<T>() where T : class;
void Add<T>(T obj);

T Get<T>();
bool TryGet<T>(out T result);

object Get(Type t);
bool TryGet(Type t, out object result);
}
}

+ 21
- 45
src/Discord.Net.Commands/ReflectionUtils.cs View File

@@ -1,5 +1,4 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Reflection;

@@ -9,62 +8,39 @@ namespace Discord.Commands
{
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[] arguments = null;

var constructors = typeInfo.DeclaredConstructors.ToArray();
if (constructors.Length == 0)
throw new InvalidOperationException($"No constructor found for \"{typeInfo.FullName}\"");
else if (constructors.Length > 1)
throw new InvalidOperationException($"Multiple constructors found for \"{typeInfo.FullName}\"");

var constructor = constructors[0];
ParameterInfo[] parameters = constructor.GetParameters();

// TODO: can this logic be made better/cleaner?
if (parameters.Length == 1)
object[] args = new object[parameters.Length];
for (int i = 0; i < parameters.Length; i++)
{
if (parameters[0].ParameterType == typeof(IDependencyMap))
var parameter = parameters[i];
object arg;
if (map == null || !map.TryGet(parameter.ParameterType, out arg))
{
if (map != null)
arguments = new object[] { map };
else
throw new InvalidOperationException($"Could not find a valid constructor for \"{typeInfo.FullName}\" (an IDependencyMap is required)");
}
}
else if (parameters.Length == 2)
{
if (parameters[0].ParameterType == typeof(CommandService) && parameters[1].ParameterType == typeof(IDependencyMap))
if (map != null)
arguments = new object[] { service, map };
if (parameter.ParameterType == typeof(CommandService))
arg = service;
else if (parameter.ParameterType == typeof(IDependencyMap))
arg = map;
else
throw new InvalidOperationException($"Could not find a valid constructor for \"{typeInfo.FullName}\" (an IDependencyMap is required)");
}

if (arguments == null)
{
try
{
// TODO: probably change this ternary into something sensible?
arguments = parameters.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}\" (an IDependencyMap is required)", ex);
throw new InvalidOperationException($"Failed to create \"{typeInfo.FullName}\", dependency \"{parameter.ParameterType.Name}\" was not found.");
}
args[i] = arg;
}

try
{
return constructor.Invoke(arguments);
return constructor.Invoke(args);
}
catch (Exception ex)
{
throw new InvalidOperationException($"Could not create \"{typeInfo.FullName}\"", ex);
throw new Exception($"Failed to create \"{typeInfo.FullName}\"", ex);
}
}
}


Loading…
Cancel
Save