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.

References