Fixed modals with value type properties (#3091)

* Fixed type reader/converter parsing exception

* Fixed modals with value types properties

* Made OverridesToString result lazy and store it
This commit is contained in:
Suiram1701
2025-04-26 21:40:21 +02:00
committed by GitHub
parent 9b79f0b27b
commit a8523c5ebd
3 changed files with 44 additions and 3 deletions

View File

@@ -68,8 +68,13 @@ namespace Discord.Interactions
{
case TextInputComponentInfo textComponent:
{
var boxedValue = textComponent.Getter(modal);
var value = textComponent.TypeOverridesToString
? boxedValue.ToString()
: boxedValue as string;
builder.AddTextInput(textComponent.Label, textComponent.CustomId, textComponent.Style, textComponent.Placeholder, textComponent.IsRequired ? textComponent.MinLength : null,
textComponent.MaxLength, textComponent.IsRequired, textComponent.Getter(modal) as string);
textComponent.MaxLength, textComponent.IsRequired, value);
}
break;
default:

View File

@@ -1,3 +1,5 @@
using System;
namespace Discord.Interactions
{
/// <summary>
@@ -5,6 +7,12 @@ namespace Discord.Interactions
/// </summary>
public class TextInputComponentInfo : InputComponentInfo
{
/// <summary>
/// <c>true</c> when <see cref="InputComponentInfo.Type"/> overrides <see cref="object.ToString"/>.
/// </summary>
internal bool TypeOverridesToString => _typeOverridesToString.Value;
private readonly Lazy<bool> _typeOverridesToString;
/// <summary>
/// Gets the style of the text input.
/// </summary>
@@ -37,6 +45,8 @@ namespace Discord.Interactions
MinLength = builder.MinLength;
MaxLength = builder.MaxLength;
InitialValue = builder.InitialValue;
_typeOverridesToString = new(() => ReflectionUtils<object>.OverridesToString(Type));
}
}
}

View File

@@ -177,7 +177,8 @@ namespace Discord.Interactions
{
var instanceParam = Expression.Parameter(typeof(T), "instance");
var prop = Expression.Property(instanceParam, propertyInfo);
return Expression.Lambda<Func<T, object>>(prop, instanceParam).Compile();
var cast = Expression.Convert(prop, typeof(object));
return Expression.Lambda<Func<T, object>>(cast, instanceParam).Compile();
}
internal static Func<T, object> CreateLambdaPropertyGetter(Type type, PropertyInfo propertyInfo)
@@ -185,7 +186,8 @@ namespace Discord.Interactions
var instanceParam = Expression.Parameter(typeof(T), "instance");
var instanceAccess = Expression.Convert(instanceParam, type);
var prop = Expression.Property(instanceAccess, propertyInfo);
return Expression.Lambda<Func<T, object>>(prop, instanceParam).Compile();
var cast = Expression.Convert(prop, typeof(object));
return Expression.Lambda<Func<T, object>>(cast, instanceParam).Compile();
}
internal static Func<object[], object[], T> CreateLambdaMemberInit(TypeInfo typeInfo, ConstructorInfo constructor, Predicate<PropertyInfo> propertySelect = null)
@@ -227,5 +229,29 @@ namespace Discord.Interactions
return instance;
};
}
/// <summary>
/// Checks whether <paramref name="type"/> or any base type of it overrides <see cref="object.ToString"/>.
/// </summary>
/// <param name="type">The type to check. If <c>null</c> <typeparamref name="T"/> will be used.</param>
internal static bool OverridesToString(Type type = null)
{
type ??= typeof(T);
do
{
#if NET6_0_OR_GREATER
var method = type.GetMethod(nameof(ToString), bindingAttr: BindingFlags.Public | BindingFlags.Instance, types: Type.EmptyTypes);
#else
var method = type.GetMethods(BindingFlags.Public | BindingFlags.Instance)
.SingleOrDefault(m => m.Name == nameof(ToString) && m.GetParameters().Length == 0);
#endif
if (method != null)
return true;
}
while ((type = type.BaseType) != typeof(object));
return false;
}
}
}