Collections, dictionaries and wrappers
editTag the elements of a collection
On a collection, a Nullable<T>, a Task<T>, a ValueTask<T>, a Lazy<T>, a span, or a memory, the tag describes the element or the value, not the container:
[ValueTag("OrderId")] public List<Guid> OrderIds { get; } = [];
public void M(Order order)
{
OrderIds.Add(order.ProjectId); // MFTV0002
_ = OrderIds.Where(id => id == order.ProjectId); // MFTV0001
Load(OrderIds.Where(id => id != Guid.Empty).First()); // ok
}The tag flows through indexers, foreach, LINQ, lambda parameters (including IQueryable expression trees), ConfigureAwait, WithCancellation, and any generic method whose signature preserves the element type.
A string is not a collection: the tag of a string describes the string, not its characters.
Tag the keys and values of a dictionary
Use Key and Value for dictionaries:
[ValueTag(Key = "OrderId", Value = "ProjectId")]
public Dictionary<Guid, Guid> ProjectIdByOrderId { get; } = [];- Either one can be omitted, to tag only the keys or only the values.
- A dictionary declaration tagged with
[ValueTag("Tag")]instead ofKeyandValueis reported, and so areKeyandValueon a type that is not a dictionary (MFTV0005). An attribute cannot combine tags withKeyandValue. - For a local variable, use the comment
// ValueTag Key=OrderId Value=ProjectId, or tag the type arguments. See Tagging local variables.
Keep the tags of projections
Anonymous type properties take the tag of their initializer, so projections keep their tags. A collection initializer takes the tags of the elements it adds:
var rows = orders.Select(order => new { order.Id, order.ProjectId });
foreach (var row in rows)
{
Load(row.Id); // ok
Load(row.ProjectId); // MFTV0002
}
var ids = new List<Guid> { orders[0].Id }; // a list of OrderIds
Load(ids[0]); // okIn the same way, new Dictionary<Guid, Guid> { [order.Id] = order.ProjectId } maps OrderIds to ProjectIds.
Elements that are checked
Adding a value to a tagged collection is a flow: the value must have the tag of the elements (MFTV0002). The elements of an array, a collection expression, or a collection initializer must share a tag (MFTV0003). The arguments of params and the elements of a collection of object are not combined, as they hold values of different kinds, such as the arguments of a log message.