Use Params For Variable Args
ID |
csharp.use_params_for_variable_args |
Severity |
low |
Remediation Complexity |
medium |
Remediation Risk |
low |
Remediation Effort |
medium |
Resource |
Code Smell |
Language |
CSharp |
Tags |
api-design, code_smell |
Description
Reports public methods whose last parameter is an object[] or string[] array
without the params modifier. The params modifier lets callers pass values
directly (Foo(a, b, c)) instead of constructing a temporary array
(Foo(new[] { a, b, c })).
Rationale
params is the .NET-idiomatic shape for variadic public APIs. It costs nothing
at the callee (the array is still received as a single parameter) and removes a
syntactic ceremony from every call site. Reserving it to non-public overloads
makes the API harder to use without adding flexibility.
An override and a member implementing a method of an interface the containing type implements
(when that interface is declared in the same file) are not reported either: the array-vs-params
shape there is not this declaration’s to change on its own — adding params only to the
implementation helps no caller going through the base type or the interface, so the report
belongs on the declaration that fixes the signature.
public interface IBus
{
void Log(string level, string[] tags);
}
public class Bus : IBus
{
public void Emit(string topic, object[] payload) { } // FLAW
public void Log(string level, string[] tags) { } // OK, implements IBus
public void Push(string topic, params object[] payload) { } // OK
public void Combine(string topic, string format) { } // OK, not an array
internal void EmitInternal(string topic, object[] payload) { } // OK, non-public
}
Remediation
Add the params modifier to the last array parameter. If the array is meant to
be passed only as a constructed array (for performance reasons or because the
contents are not user-supplied), document the choice and add an
internal/private non-params overload.