|
|
@@ -1,4 +1,5 @@ |
|
|
|
using System; |
|
|
|
using System.Collections.Generic; |
|
|
|
using System.Linq; |
|
|
|
using System.Reflection; |
|
|
|
|
|
|
@@ -6,18 +7,64 @@ namespace Discord.Commands |
|
|
|
{ |
|
|
|
internal class ReflectionUtils |
|
|
|
{ |
|
|
|
internal static object CreateObject(TypeInfo typeInfo) |
|
|
|
internal static object CreateObject(TypeInfo typeInfo, CommandService service, IDependencyMap map = null) |
|
|
|
{ |
|
|
|
var constructor = typeInfo.DeclaredConstructors.Where(x => x.GetParameters().Length == 0).FirstOrDefault(); |
|
|
|
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($"Failed to find a valid constructor for \"{typeInfo.FullName}\""); |
|
|
|
throw new InvalidOperationException($"Found no constructor for \"{typeInfo.FullName}\""); |
|
|
|
|
|
|
|
object[] arguments = null; |
|
|
|
|
|
|
|
ParameterInfo[] parameters = constructor.GetParameters(); |
|
|
|
|
|
|
|
// TODO: can this logic be made better/cleaner? |
|
|
|
if (parameters.Length == 1) |
|
|
|
{ |
|
|
|
if (parameters[0].ParameterType == typeof(IDependencyMap)) |
|
|
|
{ |
|
|
|
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 }; |
|
|
|
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); |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
try |
|
|
|
{ |
|
|
|
return constructor.Invoke(null); |
|
|
|
return constructor.Invoke(arguments); |
|
|
|
} |
|
|
|
catch (Exception ex) |
|
|
|
{ |
|
|
|
throw new InvalidOperationException($"Failed to create \"{typeInfo.FullName}\"", ex); |
|
|
|
throw new InvalidOperationException($"Could not create \"{typeInfo.FullName}\"", ex); |
|
|
|
} |
|
|
|
} |
|
|
|
} |
|
|
|