Do Not Expose Generic Lists
ID |
csharp.do_not_expose_generic_lists |
Severity |
low |
Remediation Complexity |
trivial |
Remediation Risk |
low |
Remediation Effort |
low |
Resource |
Best Practice |
Language |
CSharp |
Tags |
api_design, best_practice |
Description
Reports public or protected API members whose declared type is System.Collections.Generic.List<T>.
The .NET design guidelines recommend exposing an interface instead, so callers depend on the
contract rather than the specific implementation.
Rationale
Returning a concrete List<T> leaks the implementation. Callers can mutate the
collection, the implementation cannot later swap to a different backing structure
(immutable list, array segment, lazy view) without a breaking change, and read-only
intent cannot be communicated. IList<T>, ICollection<T> and IReadOnlyList<T> model
the relevant contracts directly.
Only members that are actually reachable from outside the declaring assembly are
reported: a public/protected member nested inside a private or internal type is
not on the external API surface (nothing outside the enclosing type can see it), and
private protected (visible only to derived types in the same assembly) does not carry
the cross-assembly binary-compatibility risk this rule targets either.
public class Inventory
{
public List<string> Items { get; } // FLAW
public List<string> Fetch(int n) => new(); // FLAW
public IReadOnlyList<string> History { get; } = new List<string>(); // OK
public IList<string> Categories { get; } // OK
public IList<string> Search(string term) => new List<string>(); // OK
}