StackExchange.Redis

SER304: repeated queued operations may suit the variadic overload

The same command is queued several times over, and one variadic call does the lot - one round-trip, atomic on the server, no transaction needed.

// flagged
var tran = db.CreateTransaction();
_ = tran.SetAddAsync(key, "a");
_ = tran.SetAddAsync(key, "b");
await tran.ExecuteAsync();

// suggested
long added = await db.SetAddAsync(key, new RedisValue[] { "a", "b" });

What it covers

One key, many values - every call must be on the same key:

Repeated Single call Server
SetAdd / SetRemove SetAdd(key, values) / SetRemove(key, values) any
SortedSetAdd / SortedSetRemove SortedSetAdd(key, entries) / SortedSetRemove(key, members) any
HashSet / HashDelete HashSet(key, entries) / HashDelete(key, fields) any
ListLeftPush / ListRightPush ListLeftPush(key, values) / ListRightPush(key, values) any
SetContains SetContains(key, values) (SMISMEMBER) 6.2

Many keys - the calls must be on different keys:

Repeated Single call Server
StringSet StringSet(KeyValuePair<RedisKey, RedisValue>[]) (MSET) any
StringGet StringGet(keys) (MGET) any
KeyDelete KeyDelete(keys) (DEL) any
KeyExists KeyExists(keys) (EXISTS) any

Which direction applies is the whole distinction: SADD takes one key and many values, so calls across different keys have no single-command form; MSET takes many keys, so calls on one key are not what this is about. Neither is flagged in the wrong direction.

Most of these variadic forms arrived in Redis 2.4, which predates anything realistically in service, so no version is mentioned. SMISMEMBER at 6.2 is recent enough to say so - see declaring your server version.

What changes when you apply it

This is why it has its own ID rather than sharing SER303: the result changes shape, not just meaning.

If your code genuinely needs to know which of the members was new, the per-call form is the right one and this suggestion is not for you - suppress it.

Cases that are deliberately not flagged

Plus everything under when these rules stay quiet.

Guidance, not a verdict

This rule is a heuristic. It reads your source text - it cannot see your keys, your server, or what you know about the code - so it is deliberately conservative and stays quiet wherever it is unsure. Everything it flags still works, and will keep working: this is a suggestion, not a defect report.

That conservatism is meant to make a false positive rare, not impossible. If you think the rule has flagged something it should not have, please report it, including the transaction as written. A rule that fires on correct code is a bug in the rule - and one that reaches every consumer of the package - so it is worth fixing rather than quietly suppressing.

Suppressing

Reported as a warning, so TreatWarningsAsErrors builds fail until you act on it or turn it down.

<NoWarn>$(NoWarn);SER304</NoWarn>

or locally:

#pragma warning disable SER304