Table of Contents

TypeConverters

TypeConverters are responsible for registering command parameters to Discord and parsing the user inputs into method parameters.

By default, TypeConverters for the following types are provided with Discord.Interactions library.

  • Implementations of IUser
  • Implementations of IChannel
  • Implementations of IRole
  • Implementations of IMentionable
  • string
  • float, double, decimal
  • bool
  • char
  • sbyte, byte
  • int16, int32, int64
  • uint16, uint32, uint64
  • enum
  • DateTime
  • TimeSpan

Creating TypeConverters

Depending on your needs, there are two types of TypeConverters you can create:

  • Concrete type
  • Generic type

A valid converter must inherit TypeConverter base type. And override the abstract base methods.

CanConvertTo() Method

This method is used by Interaction Service to search for alternative Type Converters.

Interaction Services determines the most suitable TypeConverter for a parameter type in the following order:

  1. It searches for a TypeConverter that is registered to specifically target that parameter type
  2. It searches for a TypeConverter that returns true when its CanConvertTo() method is invoked for thaty parameter type.
  3. It searches for a generic TypeConverter<T> with a matching type constraint. If there are more multiple matches, the one whose type constraint is the most specialized will be chosen.
Note

Alternatively, you can use the generic variant (TypeConverter<T>) of the TypeConverter base class which implements the following method body for CanConvertTo() method

public sealed override bool CanConvertTo (Type type) => 
    typeof(T).IsAssignableFrom(type);

GetDiscordType() Method

This method is used by InteractionService to determine the Discord Application Command Option type of a parameter type.

ReadAsync() Method

This method is used by InteractionService to parse the user input. This method should return FromSuccess if the parsing operation is successful, otherwise it should return FromError . The inner logic of this method is totally up to you, however you should avoid using long running code.

Write() Method

This method is used to configure the Discord Application Command Option before it gets registered to Discord. Command Option is configured by modifying the ApplicationCommandOptionProperties instance.

Warning

The default parameter building pipeline is isolated and will not be disturbed by the TypeConverter workflow. But changes made in this method will override the values generated by the InteractionService for a Discord Application Command Option.

Example Enum TypeConverter

internal sealed class EnumConverter<T> : TypeConverter<T> where T : struct, Enum
{
    public override ApplicationCommandOptionType GetDiscordType() => ApplicationCommandOptionType.String;

    public override Task<TypeConverterResult> ReadAsync(IInteractionCommandContext context, SocketSlashCommandDataOption option, IServiceProvider services)
    {
        if (Enum.TryParse<T>((string)option.Value, out var result))
            return Task.FromResult(TypeConverterResult.FromSuccess(result));
        else
            return Task.FromResult(TypeConverterResult.FromError(InteractionCommandError.ConvertFailed, $"Value {option.Value} cannot be converted to {nameof(T)}"));
    }

    public override void Write(ApplicationCommandOptionProperties properties, IParameterInfo parameterInfo)
    {
        var names = Enum.GetNames(typeof(T));
        if (names.Length <= 25)
        {
            var choices = new List<ApplicationCommandOptionChoiceProperties>();

            foreach (var name in names)
                choices.Add(new ApplicationCommandOptionChoiceProperties
                {
                    Name = name,
                    Value = name
                });

            properties.Choices = choices;
        }
    }
}
Important

TypeConverters must be registered prior to module discovery. If Interaction Service encounters a parameter type that doesn't belong to any of the registered [TypeConverters] during this phase, it will throw an exception.

Concrete TypeConverters

Registering Concrete TypeConverters are as simple as creating an instance of your custom converter and invoking AddTypeConverter() method.

interactionService.AddTypeConverter<string[]>(new StringArrayConverter());

Generic TypeConverters

To register a generic TypeConverter<T>, you need to invoke the AddGenericTypeConverter() method of the Interaction Service class. You need to pass the type of your TypeConverter<T> and a target base type to this method.

For instance, to register the previously mentioned enum converter the following can be used:

interactionService.AddGenericTypeConverter<Enum>(typeof(EnumConverter<>));

Interaction service checks if the target base type satisfies the type constraints of the Generic TypeConverter class.

Note

Dependencies of Generic TypeConverters are also resolved using the Dependency Injection pattern.