public static bool IsCustomRequired(this Arg argument) => argument?.CustomAttributes.OfType <RequiredAttribute>().Any() ?? false;
private void MakeCallable(MethodInfo mi, object inst, out Delegate cbl, out IReadOnlyList <CommandArgument> args) { if (!mi.IsCommandCandidate(out var ps)) { throw new MissingMethodException("Specified method is not suitable for a command."); } var ei = Expression.Constant(inst); var ea = new ParameterExpression[ps.Length]; ea[0] = Expression.Parameter(typeof(CommandContext), "ctx"); var i = 1; var ps1 = ps.Skip(1); var argsl = new List <CommandArgument>(ps.Length - 1); foreach (var xp in ps1) { var ca = new CommandArgument { Name = xp.Name, Type = xp.ParameterType, IsOptional = xp.IsOptional, DefaultValue = xp.IsOptional ? xp.DefaultValue : null }; var attrs = xp.GetCustomAttributes(); foreach (var xa in attrs) { switch (xa) { case DescriptionAttribute d: ca.Description = d.Description; break; case RemainingTextAttribute r: ca.IsCatchAll = true; break; case ParamArrayAttribute p: ca.IsCatchAll = true; ca.Type = xp.ParameterType.GetElementType(); ca._is_array = true; break; } } if (i > 1 && !ca.IsOptional && !ca.IsCatchAll && argsl[i - 2].IsOptional) { throw new InvalidOperationException("Non-optional argument cannot appear after an optional one"); } argsl.Add(ca); ea[i++] = Expression.Parameter(xp.ParameterType, xp.Name); } var ec = Expression.Call(ei, mi, ea); var el = Expression.Lambda(ec, ea); cbl = el.Compile(); args = new ReadOnlyCollection <CommandArgument>(argsl); }