From b029725bb1333a36d74f414fef23f5d24258311e Mon Sep 17 00:00:00 2001 From: RogueException Date: Wed, 20 Jul 2016 23:34:32 -0300 Subject: [PATCH] Cleaned up new DependencyMap system --- .../Dependencies/DependencyMap.cs | 41 ++++++++---- .../Dependencies/IDependencyMap.cs | 11 ++-- src/Discord.Net.Commands/ReflectionUtils.cs | 66 ++++++------------- 3 files changed, 57 insertions(+), 61 deletions(-) diff --git a/src/Discord.Net.Commands/Dependencies/DependencyMap.cs b/src/Discord.Net.Commands/Dependencies/DependencyMap.cs index db4d20984..d37d69e29 100644 --- a/src/Discord.Net.Commands/Dependencies/DependencyMap.cs +++ b/src/Discord.Net.Commands/Dependencies/DependencyMap.cs @@ -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(); } + public void Add(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() + { + 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() where T : class + public bool TryGet(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 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); } } } diff --git a/src/Discord.Net.Commands/Dependencies/IDependencyMap.cs b/src/Discord.Net.Commands/Dependencies/IDependencyMap.cs index 859cff09b..784a9bc56 100644 --- a/src/Discord.Net.Commands/Dependencies/IDependencyMap.cs +++ b/src/Discord.Net.Commands/Dependencies/IDependencyMap.cs @@ -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() where T : class; void Add(T obj); + + T Get(); + bool TryGet(out T result); + + object Get(Type t); + bool TryGet(Type t, out object result); } } diff --git a/src/Discord.Net.Commands/ReflectionUtils.cs b/src/Discord.Net.Commands/ReflectionUtils.cs index 62c77ff64..212677749 100644 --- a/src/Discord.Net.Commands/ReflectionUtils.cs +++ b/src/Discord.Net.Commands/ReflectionUtils.cs @@ -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); } } }