/// <summary> /// Initializes a new interpreter and discovers methods marked /// with <see cref="CommandHandlerAttribute"/> attribute. /// </summary> protected CommandInterpreter() { var interpreters = new Dictionary <int, CommandHandler>(); var formatters = new Dictionary <Type, FormatterInfo>(); const BindingFlags publicInstanceMethod = BindingFlags.Public | BindingFlags.Instance; foreach (var method in GetType().GetMethods(publicInstanceMethod)) { var handlerAttr = method.GetCustomAttribute <CommandHandlerAttribute>(); if (handlerAttr is not null && method.ReturnType == typeof(ValueTask)) { var parameters = method.GetParameterTypes(); if (GetLength(parameters) != 2 || !parameters[0].IsValueType || parameters[1] != typeof(CancellationToken)) { continue; } var commandType = parameters[0]; var commandAttr = commandType.GetCustomAttribute <CommandAttribute>(); if (commandAttr is null || commandAttr.Formatter is null) { continue; } var formatter = new FormatterInfo(commandAttr); if (formatter.IsEmpty) { continue; } var interpreter = Delegate.CreateDelegate(typeof(Func <, ,>).MakeGenericType(commandType, typeof(CancellationToken), typeof(ValueTask)), method.IsStatic ? null : this, method); interpreters.Add(commandAttr.Id, Cast <CommandHandler>(Activator.CreateInstance(typeof(CommandHandler <>).MakeGenericType(commandType), formatter, interpreter))); formatters.Add(commandType, formatter); } } this.interpreters = CreateRegistry(interpreters); interpreters.Clear(); formatters.TrimExcess(); this.formatters = formatters; }