Browse Source

Support to read an IEnumerable property

pull/1123/head
Joe4evr 7 years ago
parent
commit
7da36190bc
2 changed files with 67 additions and 7 deletions
  1. +43
    -7
      src/Discord.Net.Commands/Readers/NamedArgumentTypeReader.cs
  2. +24
    -0
      test/Discord.Net.Tests/Tests.TypeReaders.cs

+ 43
- 7
src/Discord.Net.Commands/Readers/NamedArgumentTypeReader.cs View File

@@ -1,4 +1,5 @@
using System; using System;
using System.Collections;
using System.Collections.Generic; using System.Collections.Generic;
using System.Collections.Immutable; using System.Collections.Immutable;
using System.Linq; using System.Linq;
@@ -125,23 +126,58 @@ namespace Discord.Commands


async Task<object> ReadArgumentAsync(PropertyInfo prop, string arg) async Task<object> ReadArgumentAsync(PropertyInfo prop, string arg)
{ {
var elemType = prop.PropertyType;
bool isCollection = false;
if (elemType.GetTypeInfo().IsGenericType && elemType.GetGenericTypeDefinition() == typeof(IEnumerable<>))
{
elemType = prop.PropertyType.GenericTypeArguments[0];
isCollection = true;
}

var overridden = prop.GetCustomAttribute<OverrideTypeReaderAttribute>(); var overridden = prop.GetCustomAttribute<OverrideTypeReaderAttribute>();
var reader = (overridden != null) var reader = (overridden != null)
? ModuleClassBuilder.GetTypeReader(_commands, prop.PropertyType, overridden.TypeReader, services)
: (_commands.GetDefaultTypeReader(prop.PropertyType)
?? _commands.GetTypeReaders(prop.PropertyType).FirstOrDefault().Value);
? ModuleClassBuilder.GetTypeReader(_commands, elemType, overridden.TypeReader, services)
: (_commands.GetDefaultTypeReader(elemType)
?? _commands.GetTypeReaders(elemType).FirstOrDefault().Value);


if (reader != null) if (reader != null)
{ {
var readResult = await reader.ReadAsync(context, arg, services).ConfigureAwait(false);
return (readResult.IsSuccess)
? readResult.BestMatch
: null;
if (isCollection)
{
var method = _readMultipleMethod.MakeGenericMethod(elemType);
var task = (Task<IEnumerable>)method.Invoke(null, new object[] { reader, context, arg.Split(','), services });
return await task.ConfigureAwait(false);
}
else
return await ReadSingle(reader, context, arg, services).ConfigureAwait(false);
} }
return null; return null;
} }
} }


private static async Task<object> ReadSingle(TypeReader reader, ICommandContext context, string arg, IServiceProvider services)
{
var readResult = await reader.ReadAsync(context, arg, services).ConfigureAwait(false);
return (readResult.IsSuccess)
? readResult.BestMatch
: null;
}
private static async Task<IEnumerable> ReadMultiple<TObj>(TypeReader reader, ICommandContext context, IEnumerable<string> args, IServiceProvider services)
{
var objs = new List<TObj>();
foreach (var arg in args)
{
var read = await ReadSingle(reader, context, arg.Trim(), services).ConfigureAwait(false);
if (read != null)
objs.Add((TObj)read);
}
return objs.ToImmutableArray();
}
private static readonly MethodInfo _readMultipleMethod = typeof(NamedArgumentTypeReader<T>)
.GetTypeInfo()
.DeclaredMethods
.Single(m => m.IsPrivate && m.IsStatic && m.Name == nameof(ReadMultiple));

private enum ReadState private enum ReadState
{ {
LookingForParameter, LookingForParameter,


+ 24
- 0
test/Discord.Net.Tests/Tests.TypeReaders.cs View File

@@ -1,4 +1,5 @@
using System; using System;
using System.Collections.Generic;
using System.Threading.Tasks; using System.Threading.Tasks;
using Discord.Commands; using Discord.Commands;
using Xunit; using Xunit;
@@ -80,6 +81,27 @@ namespace Discord
Assert.False(result.IsSuccess); Assert.False(result.IsSuccess);
Assert.Equal(expected: CommandError.Exception, actual: result.Error); Assert.Equal(expected: CommandError.Exception, actual: result.Error);
} }

[Fact]
public async Task TestMultiple()
{
var commands = new CommandService();
var module = await commands.AddModuleAsync<TestModule>(null);

Assert.NotNull(module);
Assert.NotEmpty(module.Commands);

var cmd = module.Commands[0];
Assert.NotNull(cmd);
Assert.NotEmpty(cmd.Parameters);

var param = cmd.Parameters[0];
Assert.NotNull(param);
Assert.True(param.IsRemainder);

var result = await param.ParseAsync(null, "manyints: \"1, 2, 3, 4, 5, 6, 7\"");
Assert.True(result.IsSuccess);
}
} }


[NamedArgumentType] [NamedArgumentType]
@@ -89,6 +111,8 @@ namespace Discord


[OverrideTypeReader(typeof(CustomTypeReader))] [OverrideTypeReader(typeof(CustomTypeReader))]
public string Bar { get; set; } public string Bar { get; set; }

public IEnumerable<int> ManyInts { get; set; }
} }


public sealed class CustomTypeReader : TypeReader public sealed class CustomTypeReader : TypeReader


Loading…
Cancel
Save