Browse Source

Re-implement TypeReader override liogic

pull/287/head
Joe4evr 8 years ago
parent
commit
6b4ba1adb7
4 changed files with 57 additions and 15 deletions
  1. +21
    -0
      src/Discord.Net.Commands/Attributes/TypeReaderAttribute.cs
  2. +11
    -4
      src/Discord.Net.Commands/CommandInfo.cs
  3. +6
    -6
      src/Discord.Net.Commands/CommandService.cs
  4. +19
    -5
      src/Discord.Net.Commands/ModuleInfo.cs

+ 21
- 0
src/Discord.Net.Commands/Attributes/TypeReaderAttribute.cs View File

@@ -0,0 +1,21 @@
using System;
using System.Reflection;

namespace Discord.Commands.Attributes
{
[AttributeUsage(AttributeTargets.Class | AttributeTargets.Parameter, AllowMultiple = true)]
public class TypeReaderAttribute : Attribute
{
public Type Type { get; }
public TypeInfo OverridingTypeReader { get; }

public TypeReaderAttribute(Type forType, Type typeReader)
{
if (!typeof(TypeReader).GetTypeInfo().IsAssignableFrom(typeReader.GetTypeInfo()))
throw new ArgumentException($"Type of argument {nameof(typeReader)} must derive from {nameof(TypeReader)}", nameof(typeReader));

Type = forType;
OverridingTypeReader = typeReader.GetTypeInfo();
}
}
}

+ 11
- 4
src/Discord.Net.Commands/CommandInfo.cs View File

@@ -6,6 +6,7 @@ using System.Diagnostics;
using System.Linq; using System.Linq;
using System.Reflection; using System.Reflection;
using System.Threading.Tasks; using System.Threading.Tasks;
using Discord.Commands.Attributes;


namespace Discord.Commands namespace Discord.Commands
{ {
@@ -30,7 +31,7 @@ namespace Discord.Commands
public IReadOnlyList<CommandParameter> Parameters { get; } public IReadOnlyList<CommandParameter> Parameters { get; }
public IReadOnlyList<PreconditionAttribute> Preconditions { get; } public IReadOnlyList<PreconditionAttribute> Preconditions { get; }


internal CommandInfo(MethodInfo source, ModuleInfo module, CommandAttribute attribute, string groupPrefix)
internal CommandInfo(MethodInfo source, ModuleInfo module, CommandAttribute attribute, string groupPrefix, IDependencyMap dependencyMap = null)
{ {
try try
{ {
@@ -74,7 +75,7 @@ namespace Discord.Commands
var priorityAttr = source.GetCustomAttribute<PriorityAttribute>(); var priorityAttr = source.GetCustomAttribute<PriorityAttribute>();
Priority = priorityAttr?.Priority ?? 0; Priority = priorityAttr?.Priority ?? 0;


Parameters = BuildParameters(source);
Parameters = BuildParameters(source, dependencyMap);
HasVarArgs = Parameters.Count > 0 ? Parameters[Parameters.Count - 1].IsMultiple : false; HasVarArgs = Parameters.Count > 0 ? Parameters[Parameters.Count - 1].IsMultiple : false;
Preconditions = BuildPreconditions(source); Preconditions = BuildPreconditions(source);
_action = BuildAction(source); _action = BuildAction(source);
@@ -184,7 +185,7 @@ namespace Discord.Commands
return methodInfo.GetCustomAttributes<PreconditionAttribute>().ToImmutableArray(); return methodInfo.GetCustomAttributes<PreconditionAttribute>().ToImmutableArray();
} }


private IReadOnlyList<CommandParameter> BuildParameters(MethodInfo methodInfo)
private IReadOnlyList<CommandParameter> BuildParameters(MethodInfo methodInfo, IDependencyMap dependencyMap = null)
{ {
var parameters = methodInfo.GetParameters(); var parameters = methodInfo.GetParameters();


@@ -199,7 +200,13 @@ namespace Discord.Commands
if (isMultiple) if (isMultiple)
type = type.GetElementType(); type = type.GetElementType();


var reader = Module.Service.GetTypeReader(type);
var trAttr = parameter.GetCustomAttribute<TypeReaderAttribute>();

var reader = (trAttr != null && trAttr.Type == type) ?
ReflectionUtils.CreateObject<TypeReader>(trAttr.OverridingTypeReader, Module.Service, dependencyMap) :
(Module.OverridingTypeReaders.ContainsKey(type) ?
Module.OverridingTypeReaders[type] :
Module.Service.GetTypeReader(type));
var typeInfo = type.GetTypeInfo(); var typeInfo = type.GetTypeInfo();


//Detect enums //Detect enums


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

@@ -65,7 +65,7 @@ namespace Discord.Commands
} }


//Modules //Modules
public async Task<ModuleInfo> AddModule<T>()
public async Task<ModuleInfo> AddModule<T>(IDependencyMap dependencyMap = null)
{ {
await _moduleLock.WaitAsync().ConfigureAwait(false); await _moduleLock.WaitAsync().ConfigureAwait(false);
try try
@@ -80,14 +80,14 @@ namespace Discord.Commands
if (_moduleDefs.ContainsKey(typeof(T))) if (_moduleDefs.ContainsKey(typeof(T)))
throw new ArgumentException($"This module has already been added."); throw new ArgumentException($"This module has already been added.");


return AddModuleInternal(typeInfo);
return AddModuleInternal(typeInfo, dependencyMap);
} }
finally finally
{ {
_moduleLock.Release(); _moduleLock.Release();
} }
} }
public async Task<IEnumerable<ModuleInfo>> AddModules(Assembly assembly)
public async Task<IEnumerable<ModuleInfo>> AddModules(Assembly assembly, IDependencyMap dependencyMap = null)
{ {
var moduleDefs = ImmutableArray.CreateBuilder<ModuleInfo>(); var moduleDefs = ImmutableArray.CreateBuilder<ModuleInfo>();
await _moduleLock.WaitAsync().ConfigureAwait(false); await _moduleLock.WaitAsync().ConfigureAwait(false);
@@ -102,7 +102,7 @@ namespace Discord.Commands
{ {
var dontAutoLoad = typeInfo.GetCustomAttribute<DontAutoLoadAttribute>(); var dontAutoLoad = typeInfo.GetCustomAttribute<DontAutoLoadAttribute>();
if (dontAutoLoad == null && !typeInfo.IsAbstract) if (dontAutoLoad == null && !typeInfo.IsAbstract)
moduleDefs.Add(AddModuleInternal(typeInfo));
moduleDefs.Add(AddModuleInternal(typeInfo, dependencyMap));
} }
} }
} }
@@ -113,9 +113,9 @@ namespace Discord.Commands
_moduleLock.Release(); _moduleLock.Release();
} }
} }
private ModuleInfo AddModuleInternal(TypeInfo typeInfo)
private ModuleInfo AddModuleInternal(TypeInfo typeInfo, IDependencyMap dependencyMap = null)
{ {
var moduleDef = new ModuleInfo(typeInfo, this);
var moduleDef = new ModuleInfo(typeInfo, this, dependencyMap);
_moduleDefs[typeInfo.AsType()] = moduleDef; _moduleDefs[typeInfo.AsType()] = moduleDef;


foreach (var cmd in moduleDef.Commands) foreach (var cmd in moduleDef.Commands)


+ 19
- 5
src/Discord.Net.Commands/ModuleInfo.cs View File

@@ -3,6 +3,7 @@ using System.Collections.Generic;
using System.Collections.Immutable; using System.Collections.Immutable;
using System.Diagnostics; using System.Diagnostics;
using System.Reflection; using System.Reflection;
using Discord.Commands.Attributes;


namespace Discord.Commands namespace Discord.Commands
{ {
@@ -19,8 +20,9 @@ namespace Discord.Commands
public string Remarks { get; } public string Remarks { get; }
public IEnumerable<CommandInfo> Commands { get; } public IEnumerable<CommandInfo> Commands { get; }
public IReadOnlyList<PreconditionAttribute> Preconditions { get; } public IReadOnlyList<PreconditionAttribute> Preconditions { get; }
public ImmutableDictionary<Type, TypeReader> OverridingTypeReaders { get; }


internal ModuleInfo(TypeInfo source, CommandService service)
internal ModuleInfo(TypeInfo source, CommandService service, IDependencyMap dependencyMap = null)
{ {
Source = source; Source = source;
Service = service; Service = service;
@@ -45,19 +47,31 @@ namespace Discord.Commands
if (remarksAttr != null) if (remarksAttr != null)
Remarks = remarksAttr.Text; Remarks = remarksAttr.Text;


var typeReaders = new Dictionary<Type, TypeReader>();

var trAttrs = source.GetCustomAttributes<TypeReaderAttribute>();
foreach (var trAttr in trAttrs)
typeReaders[trAttr.Type] = GetOverridingTypeReader(trAttr, dependencyMap);

OverridingTypeReaders = typeReaders.ToImmutableDictionary();

List<CommandInfo> commands = new List<CommandInfo>(); List<CommandInfo> commands = new List<CommandInfo>();
SearchClass(source, commands, Prefix);
SearchClass(source, commands, Prefix, dependencyMap);
Commands = commands; Commands = commands;


Preconditions = Source.GetCustomAttributes<PreconditionAttribute>().ToImmutableArray(); Preconditions = Source.GetCustomAttributes<PreconditionAttribute>().ToImmutableArray();
} }
private void SearchClass(TypeInfo parentType, List<CommandInfo> commands, string groupPrefix)

private TypeReader GetOverridingTypeReader(TypeReaderAttribute trAttr, IDependencyMap dependencyMap = null)
=> ReflectionUtils.CreateObject<TypeReader>(trAttr.OverridingTypeReader, Service, dependencyMap);

private void SearchClass(TypeInfo parentType, List<CommandInfo> commands, string groupPrefix, IDependencyMap dependencyMap = null)
{ {
foreach (var method in parentType.DeclaredMethods) foreach (var method in parentType.DeclaredMethods)
{ {
var cmdAttr = method.GetCustomAttribute<CommandAttribute>(); var cmdAttr = method.GetCustomAttribute<CommandAttribute>();
if (cmdAttr != null) if (cmdAttr != null)
commands.Add(new CommandInfo(method, this, cmdAttr, groupPrefix));
commands.Add(new CommandInfo(method, this, cmdAttr, groupPrefix, dependencyMap));
} }
foreach (var type in parentType.DeclaredNestedTypes) foreach (var type in parentType.DeclaredNestedTypes)
{ {
@@ -71,7 +85,7 @@ namespace Discord.Commands
else else
nextGroupPrefix = groupAttrib.Prefix ?? type.Name.ToLowerInvariant(); nextGroupPrefix = groupAttrib.Prefix ?? type.Name.ToLowerInvariant();


SearchClass(type, commands, nextGroupPrefix);
SearchClass(type, commands, nextGroupPrefix, dependencyMap);
} }
} }
} }


Loading…
Cancel
Save