From 62a872428b5f26dc3a8a5af08c5121558a8a8c3a Mon Sep 17 00:00:00 2001 From: Paulo Date: Mon, 20 Apr 2020 06:39:54 -0300 Subject: [PATCH 1/6] Change priority to user type readers and implement user entity readers --- .../Builders/ModuleClassBuilder.cs | 10 ++- src/Discord.Net.Commands/CommandService.cs | 73 ++++++++++++------- 2 files changed, 53 insertions(+), 30 deletions(-) diff --git a/src/Discord.Net.Commands/Builders/ModuleClassBuilder.cs b/src/Discord.Net.Commands/Builders/ModuleClassBuilder.cs index aec8dcbe3..2d909f978 100644 --- a/src/Discord.Net.Commands/Builders/ModuleClassBuilder.cs +++ b/src/Discord.Net.Commands/Builders/ModuleClassBuilder.cs @@ -275,8 +275,8 @@ private static void BuildParameter(ParameterBuilder builder, System.Reflection.P if (builder.TypeReader == null) { - builder.TypeReader = service.GetDefaultTypeReader(paramType) - ?? service.GetTypeReaders(paramType)?.FirstOrDefault().Value; + builder.TypeReader = service.GetTypeReaders(paramType)?.FirstOrDefault().Value + ?? service.GetDefaultTypeReader(paramType); } } @@ -290,9 +290,13 @@ internal static TypeReader GetTypeReader(CommandService service, Type paramType, return reader; } + var overrideTypeReader = service.GetOverrideTypeReader(paramType); + if (overrideTypeReader != null) + return overrideTypeReader; + //We dont have a cached type reader, create one reader = ReflectionUtils.CreateObject(typeReaderType.GetTypeInfo(), service, services); - service.AddTypeReader(paramType, reader, false); + service.AddOverrideTypeReader(paramType, reader); return reader; } diff --git a/src/Discord.Net.Commands/CommandService.cs b/src/Discord.Net.Commands/CommandService.cs index d5c060fe4..b22337559 100644 --- a/src/Discord.Net.Commands/CommandService.cs +++ b/src/Discord.Net.Commands/CommandService.cs @@ -49,6 +49,7 @@ public class CommandService : IDisposable private readonly ConcurrentDictionary _typedModuleDefs; private readonly ConcurrentDictionary> _typeReaders; private readonly ConcurrentDictionary _defaultTypeReaders; + private readonly ConcurrentDictionary _overrideTypeReaders; private readonly ImmutableList<(Type EntityType, Type TypeReaderType)> _entityTypeReaders; private readonly HashSet _moduleDefs; private readonly CommandMap _map; @@ -109,6 +110,7 @@ public CommandService(CommandServiceConfig config) _moduleDefs = new HashSet(); _map = new CommandMap(this); _typeReaders = new ConcurrentDictionary>(); + _overrideTypeReaders = new ConcurrentDictionary(); _defaultTypeReaders = new ConcurrentDictionary(); foreach (var type in PrimitiveParsers.SupportedTypes) @@ -348,10 +350,11 @@ public void AddTypeReader(TypeReader reader) /// An instance of the to be added. public void AddTypeReader(Type type, TypeReader reader) { - if (_defaultTypeReaders.ContainsKey(type)) - _ = _cmdLogger.WarningAsync($"The default TypeReader for {type.FullName} was replaced by {reader.GetType().FullName}." + - "To suppress this message, use AddTypeReader(reader, true)."); - AddTypeReader(type, reader, true); + var readers = _typeReaders.GetOrAdd(type, x => new ConcurrentDictionary()); + readers[reader.GetType()] = reader; + + if (type.GetTypeInfo().IsValueType) + AddNullableTypeReader(type, reader); } /// /// Adds a custom to this for the supplied object @@ -365,8 +368,9 @@ public void AddTypeReader(Type type, TypeReader reader) /// Defines whether the should replace the default one for /// if it exists. /// + [Obsolete("This method is deprecated. Use the method without the replaceDefault argument.")] public void AddTypeReader(TypeReader reader, bool replaceDefault) - => AddTypeReader(typeof(T), reader, replaceDefault); + => AddTypeReader(typeof(T), reader); /// /// Adds a custom to this for the supplied object /// type. @@ -379,27 +383,10 @@ public void AddTypeReader(TypeReader reader, bool replaceDefault) /// Defines whether the should replace the default one for if /// it exists. /// + [Obsolete("This method is deprecated. Use the method without the replaceDefault argument.")] public void AddTypeReader(Type type, TypeReader reader, bool replaceDefault) - { - if (replaceDefault && HasDefaultTypeReader(type)) - { - _defaultTypeReaders.AddOrUpdate(type, reader, (k, v) => reader); - if (type.GetTypeInfo().IsValueType) - { - var nullableType = typeof(Nullable<>).MakeGenericType(type); - var nullableReader = NullableTypeReader.Create(type, reader); - _defaultTypeReaders.AddOrUpdate(nullableType, nullableReader, (k, v) => nullableReader); - } - } - else - { - var readers = _typeReaders.GetOrAdd(type, x => new ConcurrentDictionary()); - readers[reader.GetType()] = reader; + => AddTypeReader(type, reader); - if (type.GetTypeInfo().IsValueType) - AddNullableTypeReader(type, reader); - } - } internal bool HasDefaultTypeReader(Type type) { if (_defaultTypeReaders.ContainsKey(type)) @@ -408,7 +395,7 @@ internal bool HasDefaultTypeReader(Type type) var typeInfo = type.GetTypeInfo(); if (typeInfo.IsEnum) return true; - return _entityTypeReaders.Any(x => type == x.EntityType || typeInfo.ImplementedInterfaces.Contains(x.TypeReaderType)); + return _entityTypeReaders.Any(x => type == x.EntityType || typeInfo.ImplementedInterfaces.Contains(x.EntityType)); } internal void AddNullableTypeReader(Type valueType, TypeReader valueTypeReader) { @@ -416,11 +403,43 @@ internal void AddNullableTypeReader(Type valueType, TypeReader valueTypeReader) var nullableReader = NullableTypeReader.Create(valueType, valueTypeReader); readers[nullableReader.GetType()] = nullableReader; } + internal void AddOverrideTypeReader(Type valueType, TypeReader valueTypeReader) + { + _overrideTypeReaders[valueType] = valueTypeReader; + } + internal TypeReader GetOverrideTypeReader(Type type) + { + if (_overrideTypeReaders.TryGetValue(type, out var definedTypeReader)) + return definedTypeReader; + return null; + } internal IDictionary GetTypeReaders(Type type) { if (_typeReaders.TryGetValue(type, out var definedTypeReaders)) return definedTypeReaders; - return null; + + var entityReaders = _typeReaders.Where(x => x.Key.IsAssignableFrom(type)); + + int assignableTo = -1; + KeyValuePair>? typeReader = null; + foreach (var entityReader in entityReaders) + { + int assignables = entityReaders.Sum(x => !x.Equals(entityReader) && x.Key.IsAssignableFrom(entityReader.Key) ? 1 : 0); + if (assignableTo == -1) + { + // First time + assignableTo = assignables; + typeReader = entityReader; + } + // Try to get the "higher" interface. IMessageChannel is assignable to IChannel, but not the inverse + else if (assignables > assignableTo) + { + assignableTo = assignables; + typeReader = entityReader; + } + } + + return typeReader?.Value; } internal TypeReader GetDefaultTypeReader(Type type) { @@ -511,7 +530,7 @@ public async Task ExecuteAsync(ICommandContext context, string input, I await _commandExecutedEvent.InvokeAsync(Optional.Create(), context, searchResult).ConfigureAwait(false); return searchResult; } - + var commands = searchResult.Commands; var preconditionResults = new Dictionary(); From bf144d605a3577809472cb88f2c3005c3979e242 Mon Sep 17 00:00:00 2001 From: SubZero0 Date: Fri, 26 Jun 2020 13:31:38 -0300 Subject: [PATCH 2/6] Add AddEntityTypeReader --- src/Discord.Net.Commands/CommandService.cs | 72 ++++++++++++++++++---- 1 file changed, 60 insertions(+), 12 deletions(-) diff --git a/src/Discord.Net.Commands/CommandService.cs b/src/Discord.Net.Commands/CommandService.cs index b22337559..ff392179e 100644 --- a/src/Discord.Net.Commands/CommandService.cs +++ b/src/Discord.Net.Commands/CommandService.cs @@ -48,6 +48,7 @@ public class CommandService : IDisposable private readonly SemaphoreSlim _moduleLock; private readonly ConcurrentDictionary _typedModuleDefs; private readonly ConcurrentDictionary> _typeReaders; + private readonly ConcurrentDictionary> _userEntityTypeReaders; private readonly ConcurrentDictionary _defaultTypeReaders; private readonly ConcurrentDictionary _overrideTypeReaders; private readonly ImmutableList<(Type EntityType, Type TypeReaderType)> _entityTypeReaders; @@ -78,6 +79,15 @@ public class CommandService : IDisposable /// public ILookup TypeReaders => _typeReaders.SelectMany(x => x.Value.Select(y => new { y.Key, y.Value })).ToLookup(x => x.Key, x => x.Value); + /// + /// Represents all entity type reader s loaded within . + /// + /// + /// A that the key is the object type to be read by the + /// and the element is the type of the generic definition. + /// + public ILookup EntityTypeReaders => _userEntityTypeReaders.SelectMany(x => x.Value.Select(y => new { x.Key, TypeReaderType = y })).ToLookup(x => x.Key, y => y.TypeReaderType); + /// /// Initializes a new class. /// @@ -110,6 +120,7 @@ public CommandService(CommandServiceConfig config) _moduleDefs = new HashSet(); _map = new CommandMap(this); _typeReaders = new ConcurrentDictionary>(); + _userEntityTypeReaders = new ConcurrentDictionary>(); _overrideTypeReaders = new ConcurrentDictionary(); _defaultTypeReaders = new ConcurrentDictionary(); @@ -331,8 +342,6 @@ private bool RemoveModuleInternal(ModuleInfo module) /// type. /// If is a , a nullable will /// also be added. - /// If a default exists for , a warning will be logged - /// and the default will be replaced. /// /// The object type to be read by the . /// An instance of the to be added. @@ -343,8 +352,6 @@ public void AddTypeReader(TypeReader reader) /// type. /// If is a , a nullable for the /// value type will also be added. - /// If a default exists for , a warning will be logged and - /// the default will be replaced. /// /// A instance for the type to be read. /// An instance of the to be added. @@ -357,6 +364,40 @@ public void AddTypeReader(Type type, TypeReader reader) AddNullableTypeReader(type, reader); } /// + /// Adds a custom entity to this for the supplied + /// object type. + /// + /// The object type to be read by the . + /// + /// A that is a generic type definition with a single open argument + /// of the to be added. + /// + public void AddEntityTypeReader(Type typeReaderGenericType) + => AddEntityTypeReader(typeof(T), typeReaderGenericType); + /// + /// Adds a custom entity to this for the supplied + /// object type. + /// + /// A instance for the type to be read. + /// + /// A that is a generic type definition with a single open argument + /// of the to be added. + /// + public void AddEntityTypeReader(Type type, Type typeReaderGenericType) + { + if (!typeReaderGenericType.IsGenericTypeDefinition) + throw new ArgumentException("TypeReader type must be a generic type definition.", nameof(typeReaderGenericType)); + Type[] genericArgs = typeReaderGenericType.GetGenericArguments(); + if (genericArgs.Length != 1) + throw new ArgumentException("TypeReader type must accept one and only one open generic argument.", nameof(typeReaderGenericType)); + if (!genericArgs[0].IsGenericParameter) + throw new ArgumentException("TypeReader type must accept one and only one open generic argument.", nameof(typeReaderGenericType)); + if (!genericArgs[0].GenericParameterAttributes.HasFlag(GenericParameterAttributes.ReferenceTypeConstraint)) + throw new ArgumentException("TypeReader generic argument must have a reference type constraint.", nameof(typeReaderGenericType)); + var readers = _userEntityTypeReaders.GetOrAdd(type, x => new ConcurrentQueue()); + readers.Enqueue(typeReaderGenericType); + } + /// /// Adds a custom to this for the supplied object /// type. /// If is a , a nullable will @@ -418,28 +459,35 @@ internal IDictionary GetTypeReaders(Type type) if (_typeReaders.TryGetValue(type, out var definedTypeReaders)) return definedTypeReaders; - var entityReaders = _typeReaders.Where(x => x.Key.IsAssignableFrom(type)); + var assignableEntityReaders = _userEntityTypeReaders.Where(x => x.Key.IsAssignableFrom(type)); int assignableTo = -1; - KeyValuePair>? typeReader = null; - foreach (var entityReader in entityReaders) + KeyValuePair>? entityReaders = null; + foreach (var entityReader in assignableEntityReaders) { - int assignables = entityReaders.Sum(x => !x.Equals(entityReader) && x.Key.IsAssignableFrom(entityReader.Key) ? 1 : 0); + int assignables = assignableEntityReaders.Sum(x => !x.Equals(entityReader) && x.Key.IsAssignableFrom(entityReader.Key) ? 1 : 0); if (assignableTo == -1) { // First time assignableTo = assignables; - typeReader = entityReader; + entityReaders = entityReader; } - // Try to get the "higher" interface. IMessageChannel is assignable to IChannel, but not the inverse + // Try to get the most specific type reader, i.e. IMessageChannel is assignable to IChannel, but not the inverse else if (assignables > assignableTo) { assignableTo = assignables; - typeReader = entityReader; + entityReaders = entityReader; } } - return typeReader?.Value; + if (entityReaders != null) + { + var entityTypeReaderType = entityReaders.Value.Value.First(); + TypeReader reader = Activator.CreateInstance(entityTypeReaderType.MakeGenericType(type)) as TypeReader; + AddTypeReader(type, reader); + return GetTypeReaders(type); + } + return null; } internal TypeReader GetDefaultTypeReader(Type type) { From b5425e96607da142cb46dcd4640d0e05daacf048 Mon Sep 17 00:00:00 2001 From: SubZero0 Date: Fri, 26 Jun 2020 17:00:46 -0300 Subject: [PATCH 3/6] Add example and fix param reference --- src/Discord.Net.Commands/CommandService.cs | 9 ++++-- .../Commands/CommandService.Examples.cs | 32 +++++++++++++++++++ .../Discord.Net.Examples.csproj | 1 + 3 files changed, 40 insertions(+), 2 deletions(-) create mode 100644 src/Discord.Net.Examples/Commands/CommandService.Examples.cs diff --git a/src/Discord.Net.Commands/CommandService.cs b/src/Discord.Net.Commands/CommandService.cs index ff392179e..80f9e5ce3 100644 --- a/src/Discord.Net.Commands/CommandService.cs +++ b/src/Discord.Net.Commands/CommandService.cs @@ -367,8 +367,13 @@ public void AddTypeReader(Type type, TypeReader reader) /// Adds a custom entity to this for the supplied /// object type. /// + /// + /// The following example adds a custom entity reader to this . + /// + /// /// The object type to be read by the . - /// + /// /// A that is a generic type definition with a single open argument /// of the to be added. /// @@ -379,7 +384,7 @@ public void AddEntityTypeReader(Type typeReaderGenericType) /// object type. /// /// A instance for the type to be read. - /// + /// /// A that is a generic type definition with a single open argument /// of the to be added. /// diff --git a/src/Discord.Net.Examples/Commands/CommandService.Examples.cs b/src/Discord.Net.Examples/Commands/CommandService.Examples.cs new file mode 100644 index 000000000..add383fc2 --- /dev/null +++ b/src/Discord.Net.Examples/Commands/CommandService.Examples.cs @@ -0,0 +1,32 @@ +using Discord.Commands; +using JetBrains.Annotations; +using System; +using System.Threading.Tasks; + +namespace Discord.Net.Examples.Commands +{ + [PublicAPI] + internal class CommandServiceExamples + { + #region AddEntityTypeReader + + public void AddCustomEntityReader(CommandService commandService) + { + commandService.AddEntityTypeReader(typeof(MyUserTypeReader<>)); + } + + public class MyUserTypeReader : TypeReader + where T : class, IUser + { + public override async Task ReadAsync(ICommandContext context, string input, IServiceProvider services) + { + if (ulong.TryParse(input, out var id)) + return ((await context.Client.GetUserAsync(id)) is T user) + ? TypeReaderResult.FromSuccess(user) + : TypeReaderResult.FromError(CommandError.ObjectNotFound, "User not found."); + return TypeReaderResult.FromError(CommandError.ParseFailed, "Couldn't parse input to ulong."); + } + + #endregion + } +} diff --git a/src/Discord.Net.Examples/Discord.Net.Examples.csproj b/src/Discord.Net.Examples/Discord.Net.Examples.csproj index ec0253428..1f459f2e6 100644 --- a/src/Discord.Net.Examples/Discord.Net.Examples.csproj +++ b/src/Discord.Net.Examples/Discord.Net.Examples.csproj @@ -13,6 +13,7 @@ + From 0984a65f47409fc3f1a924a06d63f32944be537f Mon Sep 17 00:00:00 2001 From: SubZero0 Date: Fri, 26 Jun 2020 17:14:12 -0300 Subject: [PATCH 4/6] Missed a bracket --- src/Discord.Net.Examples/Commands/CommandService.Examples.cs | 1 + 1 file changed, 1 insertion(+) diff --git a/src/Discord.Net.Examples/Commands/CommandService.Examples.cs b/src/Discord.Net.Examples/Commands/CommandService.Examples.cs index add383fc2..a094ebb3d 100644 --- a/src/Discord.Net.Examples/Commands/CommandService.Examples.cs +++ b/src/Discord.Net.Examples/Commands/CommandService.Examples.cs @@ -26,6 +26,7 @@ public override async Task ReadAsync(ICommandContext context, : TypeReaderResult.FromError(CommandError.ObjectNotFound, "User not found."); return TypeReaderResult.FromError(CommandError.ParseFailed, "Couldn't parse input to ulong."); } + } #endregion } From e5042e0418fff2972c273a262a25bd41dd54a398 Mon Sep 17 00:00:00 2001 From: SubZero0 Date: Fri, 26 Jun 2020 18:31:43 -0300 Subject: [PATCH 5/6] Change where to keep overriden type readers --- .../Builders/ModuleClassBuilder.cs | 21 +++++++------------ .../Builders/ParameterBuilder.cs | 5 ++--- src/Discord.Net.Commands/CommandService.cs | 18 +++------------- .../Readers/NamedArgumentTypeReader.cs | 4 ++-- .../Readers/TypeReader.cs | 1 + 5 files changed, 16 insertions(+), 33 deletions(-) diff --git a/src/Discord.Net.Commands/Builders/ModuleClassBuilder.cs b/src/Discord.Net.Commands/Builders/ModuleClassBuilder.cs index 2d909f978..c5eb1d4d3 100644 --- a/src/Discord.Net.Commands/Builders/ModuleClassBuilder.cs +++ b/src/Discord.Net.Commands/Builders/ModuleClassBuilder.cs @@ -275,28 +275,23 @@ private static void BuildParameter(ParameterBuilder builder, System.Reflection.P if (builder.TypeReader == null) { - builder.TypeReader = service.GetTypeReaders(paramType)?.FirstOrDefault().Value + builder.TypeReader = service.GetTypeReaders(paramType, false)?.FirstOrDefault().Value ?? service.GetDefaultTypeReader(paramType); } } internal static TypeReader GetTypeReader(CommandService service, Type paramType, Type typeReaderType, IServiceProvider services) { - var readers = service.GetTypeReaders(paramType); - TypeReader reader = null; + var readers = service.GetTypeReaders(paramType, true); if (readers != null) - { - if (readers.TryGetValue(typeReaderType, out reader)) - return reader; - } - - var overrideTypeReader = service.GetOverrideTypeReader(paramType); - if (overrideTypeReader != null) - return overrideTypeReader; + foreach (var kvp in readers) + if (kvp.Key == typeReaderType) + return kvp.Value; //We dont have a cached type reader, create one - reader = ReflectionUtils.CreateObject(typeReaderType.GetTypeInfo(), service, services); - service.AddOverrideTypeReader(paramType, reader); + TypeReader reader = ReflectionUtils.CreateObject(typeReaderType.GetTypeInfo(), service, services); + reader.IsOverride = true; + service.AddTypeReader(paramType, reader); return reader; } diff --git a/src/Discord.Net.Commands/Builders/ParameterBuilder.cs b/src/Discord.Net.Commands/Builders/ParameterBuilder.cs index 4ad5bfac0..f2a3ee70c 100644 --- a/src/Discord.Net.Commands/Builders/ParameterBuilder.cs +++ b/src/Discord.Net.Commands/Builders/ParameterBuilder.cs @@ -60,7 +60,7 @@ private TypeReader GetReader(Type type) if (type.GetTypeInfo().GetCustomAttribute() != null) { IsRemainder = true; - var reader = commands.GetTypeReaders(type)?.FirstOrDefault().Value; + var reader = commands.GetTypeReaders(type, false)?.FirstOrDefault().Value; if (reader == null) { Type readerType; @@ -80,8 +80,7 @@ private TypeReader GetReader(Type type) return reader; } - - var readers = commands.GetTypeReaders(type); + var readers = commands.GetTypeReaders(type, false); if (readers != null) return readers.FirstOrDefault().Value; else diff --git a/src/Discord.Net.Commands/CommandService.cs b/src/Discord.Net.Commands/CommandService.cs index 80f9e5ce3..e61f14a5b 100644 --- a/src/Discord.Net.Commands/CommandService.cs +++ b/src/Discord.Net.Commands/CommandService.cs @@ -50,7 +50,6 @@ public class CommandService : IDisposable private readonly ConcurrentDictionary> _typeReaders; private readonly ConcurrentDictionary> _userEntityTypeReaders; private readonly ConcurrentDictionary _defaultTypeReaders; - private readonly ConcurrentDictionary _overrideTypeReaders; private readonly ImmutableList<(Type EntityType, Type TypeReaderType)> _entityTypeReaders; private readonly HashSet _moduleDefs; private readonly CommandMap _map; @@ -121,7 +120,6 @@ public CommandService(CommandServiceConfig config) _map = new CommandMap(this); _typeReaders = new ConcurrentDictionary>(); _userEntityTypeReaders = new ConcurrentDictionary>(); - _overrideTypeReaders = new ConcurrentDictionary(); _defaultTypeReaders = new ConcurrentDictionary(); foreach (var type in PrimitiveParsers.SupportedTypes) @@ -449,20 +447,10 @@ internal void AddNullableTypeReader(Type valueType, TypeReader valueTypeReader) var nullableReader = NullableTypeReader.Create(valueType, valueTypeReader); readers[nullableReader.GetType()] = nullableReader; } - internal void AddOverrideTypeReader(Type valueType, TypeReader valueTypeReader) - { - _overrideTypeReaders[valueType] = valueTypeReader; - } - internal TypeReader GetOverrideTypeReader(Type type) - { - if (_overrideTypeReaders.TryGetValue(type, out var definedTypeReader)) - return definedTypeReader; - return null; - } - internal IDictionary GetTypeReaders(Type type) + internal IEnumerable> GetTypeReaders(Type type, bool includeOverride) { if (_typeReaders.TryGetValue(type, out var definedTypeReaders)) - return definedTypeReaders; + return includeOverride ? definedTypeReaders : definedTypeReaders.Where(x => !x.Value.IsOverride); var assignableEntityReaders = _userEntityTypeReaders.Where(x => x.Key.IsAssignableFrom(type)); @@ -490,7 +478,7 @@ internal IDictionary GetTypeReaders(Type type) var entityTypeReaderType = entityReaders.Value.Value.First(); TypeReader reader = Activator.CreateInstance(entityTypeReaderType.MakeGenericType(type)) as TypeReader; AddTypeReader(type, reader); - return GetTypeReaders(type); + return GetTypeReaders(type, false); } return null; } diff --git a/src/Discord.Net.Commands/Readers/NamedArgumentTypeReader.cs b/src/Discord.Net.Commands/Readers/NamedArgumentTypeReader.cs index 0adf61046..b584d29d5 100644 --- a/src/Discord.Net.Commands/Readers/NamedArgumentTypeReader.cs +++ b/src/Discord.Net.Commands/Readers/NamedArgumentTypeReader.cs @@ -136,8 +136,8 @@ async Task ReadArgumentAsync(PropertyInfo prop, string arg) var overridden = prop.GetCustomAttribute(); var reader = (overridden != null) ? ModuleClassBuilder.GetTypeReader(_commands, elemType, overridden.TypeReader, services) - : (_commands.GetDefaultTypeReader(elemType) - ?? _commands.GetTypeReaders(elemType).FirstOrDefault().Value); + : (_commands.GetTypeReaders(elemType, false)?.FirstOrDefault().Value + ?? _commands.GetDefaultTypeReader(elemType)); if (reader != null) { diff --git a/src/Discord.Net.Commands/Readers/TypeReader.cs b/src/Discord.Net.Commands/Readers/TypeReader.cs index af780993d..a071d9b53 100644 --- a/src/Discord.Net.Commands/Readers/TypeReader.cs +++ b/src/Discord.Net.Commands/Readers/TypeReader.cs @@ -8,6 +8,7 @@ namespace Discord.Commands /// public abstract class TypeReader { + internal bool IsOverride { get; set; } = false; /// /// Attempts to parse the into the desired type. /// From bb2eb645b29edb161c2ea1e4514672bc09b3489f Mon Sep 17 00:00:00 2001 From: SubZero0 Date: Sat, 27 Jun 2020 06:23:22 -0300 Subject: [PATCH 6/6] Xml docs changes --- src/Discord.Net.Commands/CommandService.cs | 21 ++++++++-------- .../Commands/CommandService.Examples.cs | 24 ++++++++++++++++++- 2 files changed, 33 insertions(+), 12 deletions(-) diff --git a/src/Discord.Net.Commands/CommandService.cs b/src/Discord.Net.Commands/CommandService.cs index e61f14a5b..4ca26c82f 100644 --- a/src/Discord.Net.Commands/CommandService.cs +++ b/src/Discord.Net.Commands/CommandService.cs @@ -82,8 +82,8 @@ public class CommandService : IDisposable /// Represents all entity type reader s loaded within . /// /// - /// A that the key is the object type to be read by the - /// and the element is the type of the generic definition. + /// A ; the key is the object type to be read by the , + /// while the element is the type of the generic definition. /// public ILookup EntityTypeReaders => _userEntityTypeReaders.SelectMany(x => x.Value.Select(y => new { x.Key, TypeReaderType = y })).ToLookup(x => x.Key, y => y.TypeReaderType); @@ -368,13 +368,10 @@ public void AddTypeReader(Type type, TypeReader reader) /// /// The following example adds a custom entity reader to this . /// + /// source="..\Discord.Net.Examples\Commands\CommandService.Examples.cs" /> /// /// The object type to be read by the . - /// - /// A that is a generic type definition with a single open argument - /// of the to be added. - /// + /// A generic type definition (with one open argument) of the . public void AddEntityTypeReader(Type typeReaderGenericType) => AddEntityTypeReader(typeof(T), typeReaderGenericType); /// @@ -382,10 +379,7 @@ public void AddEntityTypeReader(Type typeReaderGenericType) /// object type. /// /// A instance for the type to be read. - /// - /// A that is a generic type definition with a single open argument - /// of the to be added. - /// + /// A generic type definition (with one open argument) of the . public void AddEntityTypeReader(Type type, Type typeReaderGenericType) { if (!typeReaderGenericType.IsGenericTypeDefinition) @@ -406,6 +400,11 @@ public void AddEntityTypeReader(Type type, Type typeReaderGenericType) /// If is a , a nullable will /// also be added. /// + /// + /// The following example adds a custom entity reader to this . + /// + /// /// The object type to be read by the . /// An instance of the to be added. /// diff --git a/src/Discord.Net.Examples/Commands/CommandService.Examples.cs b/src/Discord.Net.Examples/Commands/CommandService.Examples.cs index a094ebb3d..ca656aaf9 100644 --- a/src/Discord.Net.Examples/Commands/CommandService.Examples.cs +++ b/src/Discord.Net.Examples/Commands/CommandService.Examples.cs @@ -10,7 +10,7 @@ internal class CommandServiceExamples { #region AddEntityTypeReader - public void AddCustomEntityReader(CommandService commandService) + public void AddCustomUserEntityReader(CommandService commandService) { commandService.AddEntityTypeReader(typeof(MyUserTypeReader<>)); } @@ -29,5 +29,27 @@ public override async Task ReadAsync(ICommandContext context, } #endregion + + #region AddEntityTypeReader2 + + public void AddCustomChannelEntityReader(CommandService commandService) + { + commandService.AddEntityTypeReader(typeof(MyUserTypeReader<>)); + } + + public class MyChannelTypeReader : TypeReader + where T : class, IChannel + { + public override async Task ReadAsync(ICommandContext context, string input, IServiceProvider services) + { + if (ulong.TryParse(input, out var id)) + return ((await context.Client.GetChannelAsync(id)) is T channel) + ? TypeReaderResult.FromSuccess(channel) + : TypeReaderResult.FromError(CommandError.ObjectNotFound, "Channel not found."); + return TypeReaderResult.FromError(CommandError.ParseFailed, "Couldn't parse input to ulong."); + } + } + + #endregion } }