Repository: dotnet/aspnetcore
File: src/Middleware/OutputCaching/src/Memory/MemoryOutputCacheStore.cs (C#)

Code before:
                            }
                        }
                    }
                }
            }
        }

        return ValueTask.CompletedTask;
    }

    /// <inheritdoc />
    public ValueTask<byte[]?> GetAsync(string key, CancellationToken cancellationToken)
    {
        ArgumentNullException.ThrowIfNull(key);

        var entry = _cache.Get(key) as byte[];
        return ValueTask.FromResult(entry);
    }

    /// <inheritdoc />
    public ValueTask SetAsync(string key, byte[] value, string[]? tags, TimeSpan validFor, CancellationToken cancellationToken)
    {
        ArgumentNullException.ThrowIfNull(key);
        ArgumentNullException.ThrowIfNull(value);

        var entryId = Guid.NewGuid().ToString();

        if (tags != null)
        {
            // Lock with SetEntry() to prevent EvictByTagAsync() from trying to remove a tag whose entry hasn't been added yet.
            // It might be acceptable to not lock SetEntry() since in this case Remove(key) would just no-op and the user retry to evict.

            lock (_tagsLock)
            {
                foreach (var tag in tags)
                {
                    if (tag is null)
                    {
                        throw new ArgumentException(Resources.TagCannotBeNull);
                    }

                    if (!_taggedEntries.TryGetValue(tag, out var keys))
                    {
                        keys = new HashSet<Tuple<string, string>>();
                        _taggedEntries[tag] = keys;
                    }

                    Debug.Assert(keys != null);

                    keys.Add(Tuple.Create(key, entryId));
                }

Review comment (suggestion):
Can the `Guid` be used? So that no string alloction occurs.

Code after:
                            }
                        }
                    }
                }
            }
        }

        return ValueTask.CompletedTask;
    }

    /// <inheritdoc />
    public ValueTask<byte[]?> GetAsync(string key, CancellationToken cancellationToken)
    {
        ArgumentNullException.ThrowIfNull(key);

        var entry = _cache.Get(key) as byte[];
        return ValueTask.FromResult(entry);
    }

    /// <inheritdoc />
    public ValueTask SetAsync(string key, byte[] value, string[]? tags, TimeSpan validFor, CancellationToken cancellationToken)
    {
        ArgumentNullException.ThrowIfNull(key);
        ArgumentNullException.ThrowIfNull(value);

        var entryId = Guid.NewGuid();

        if (tags != null)
        {
            // Lock with SetEntry() to prevent EvictByTagAsync() from trying to remove a tag whose entry hasn't been added yet.
            // It might be acceptable to not lock SetEntry() since in this case Remove(key) would just no-op and the user retry to evict.

            lock (_tagsLock)
            {
                foreach (var tag in tags)
                {
                    if (tag is null)
                    {
                        throw new ArgumentException(Resources.TagCannotBeNull);
                    }

                    if (!_taggedEntries.TryGetValue(tag, out var keys))
                    {
                        keys = new HashSet<TaggedEntry>();
                        _taggedEntries[tag] = keys;
                    }

                    Debug.Assert(keys != null);

                    keys.Add(new TaggedEntry(key, entryId));
                }