Skip to content

Commit 7d371b3

Browse files
committed
Refactor method matching logic in InlineQueryHandler
Refactored the method matching logic by replacing `IsValidMethod` with `TryMatchMethod` to improve flexibility and support placeholders in commands. Added helper methods `IsPlaceholder` and `PlaceholderName` for placeholder handling. Enhanced argument parsing with type validation and conversion using `TryConvertToType`. Improved ambiguity handling with detailed error messages for multiple matches. Introduced an exact match shortcut for methods without parameters. Cleaned up code for better readability and maintainability.
1 parent 9b94759 commit 7d371b3

File tree

1 file changed

+70
-31
lines changed

1 file changed

+70
-31
lines changed

Sources/TelegramBot/Handlers/InlineQueryHandler.cs

Lines changed: 70 additions & 31 deletions
Original file line numberDiff line numberDiff line change
@@ -25,83 +25,122 @@ public InlineQueryHandler(IReadOnlyCollection<MethodInfo> controllerMethods, Upd
2525
{
2626
return null;
2727
}
28+
2829
var inlineQuery = update.CallbackQuery;
2930
string command = inlineQuery.Data!;
30-
List<MethodInfo> methods = new List<MethodInfo>();
31+
32+
// Collect all candidate methods with their parsed arguments
33+
var candidates = new List<(MethodInfo Method, List<object> Args)>();
3134
foreach (var method in controllerMethods)
3235
{
33-
bool isValidMethod = IsValidMethod(method, command);
34-
if (isValidMethod)
36+
if (TryMatchMethod(method, command, out var args))
3537
{
36-
methods.Add(method);
38+
candidates.Add((method, args));
3739
}
3840
}
39-
if (methods.Count == 1)
41+
42+
if (candidates.Count == 1)
4043
{
41-
var args = _args.ToArray();
42-
ObjectHelpers.TryConvertParameters(methods[0], args);
44+
var (method, rawArgs) = candidates[0];
45+
var argsArray = rawArgs.ToArray();
46+
ObjectHelpers.TryConvertParameters(method, argsArray);
4347
_args.Clear();
44-
_args.AddRange(args);
45-
return methods[0];
48+
_args.AddRange(argsArray);
49+
return method;
4650
}
47-
else if (methods.Count > 1)
51+
52+
if (candidates.Count > 1)
4853
{
49-
throw new AmbiguousMatchException("Multiple methods found with the same command and arguments: " + command + "\n" +
50-
string.Join("\n", methods.Select(m => m.Name + " - " + m.GetParameters().Length + " parameters")));
54+
throw new AmbiguousMatchException("Multiple methods found with the same command and arguments: " + command + "\n" +
55+
string.Join("\n", candidates.Select(c => c.Method.Name + " - " + c.Method.GetParameters().Length + " parameters")));
5156
}
57+
5258
return null;
5359
}
5460

55-
private bool IsValidMethod(MethodInfo method, string command)
61+
private static bool IsPlaceholder(string segment)
5662
{
57-
var attributes = method.GetCustomAttributes(typeof(InlineCommandAttribute), false);
58-
string[] incomingCommandParts = command.Split('/');
63+
return segment.Length > 1 && segment[0] == '{' && segment[segment.Length - 1] == '}';
64+
}
65+
66+
private static string PlaceholderName(string segment)
67+
{
68+
return segment.Trim('{', '}');
69+
}
70+
71+
private bool TryMatchMethod(MethodInfo method, string command, out List<object> args)
72+
{
73+
args = new List<object>();
74+
75+
var attributes = method.GetCustomAttributes(typeof(InlineCommandAttribute), inherit: false);
76+
if (attributes.Length == 0)
77+
{
78+
return false;
79+
}
80+
81+
var incomingCommandParts = command.Split('/');
82+
var methodParameters = method.GetParameters();
5983

6084
foreach (var attribute in attributes)
6185
{
62-
if (!(attribute is InlineCommandAttribute botAttribute) // Skip if the attribute is not of type InlineCommandAttribute
63-
|| (method.GetParameters().Length == 0 && botAttribute.Command != command)) // Skip methods without parameters if the command does not match
86+
if (!(attribute is InlineCommandAttribute botAttribute))
87+
{
88+
continue;
89+
}
90+
91+
var controllerCommandParts = botAttribute.Command.Split('/');
92+
93+
// Exact match shortcut for methods without parameters
94+
if (methodParameters.Length == 0)
6495
{
65-
continue;
96+
if (string.Equals(botAttribute.Command, command, StringComparison.Ordinal))
97+
{
98+
return true;
99+
}
100+
continue;
66101
}
67102

68-
string[] controllerCommandParts = botAttribute.Command.Split('/');
69103
if (controllerCommandParts.Length != incomingCommandParts.Length)
70104
{
71105
continue;
72106
}
73107

108+
var tempArgs = new List<object>(incomingCommandParts.Length);
74109
bool match = true;
110+
75111
for (int i = 0; i < controllerCommandParts.Length; i++)
76112
{
77-
if (controllerCommandParts[i] != incomingCommandParts[i]
78-
&& !controllerCommandParts[i].StartsWith('{')
79-
&& !controllerCommandParts[i].EndsWith('}'))
80-
{
81-
match = false;
82-
break;
83-
}
113+
var controllerPart = controllerCommandParts[i];
114+
var incomingPart = incomingCommandParts[i];
84115

85-
if (controllerCommandParts[i].StartsWith('{') && controllerCommandParts[i].EndsWith('}'))
116+
if (IsPlaceholder(controllerPart))
86117
{
87-
var parameter = method.GetParameters().FirstOrDefault(p => p.Name == controllerCommandParts[i].Trim('{', '}'));
118+
var name = PlaceholderName(controllerPart);
119+
var parameter = methodParameters.FirstOrDefault(p => p.Name == name);
88120
if (parameter != null)
89121
{
90-
if (!TryConvertToType(incomingCommandParts[i], parameter.ParameterType))
122+
if (!TryConvertToType(incomingPart, parameter.ParameterType))
91123
{
92-
match = false; // If type conversion fails, break the match
124+
match = false;
93125
break;
94126
}
95127
}
96-
_args.Add(incomingCommandParts[i]);
128+
tempArgs.Add(incomingPart);
129+
}
130+
else if (!string.Equals(controllerPart, incomingPart, StringComparison.Ordinal))
131+
{
132+
match = false;
133+
break;
97134
}
98135
}
99136

100137
if (match)
101138
{
139+
args = tempArgs;
102140
return true;
103141
}
104142
}
143+
105144
return false;
106145
}
107146

0 commit comments

Comments
 (0)