λ0001: Disallowed use of TryGetValue
TryGetValue should not be used.
Cause
TryGetValue is used outside one of the allowed use cases.
Reason for rule
TryGetValue is an advanced API that is needed to interoperate with imperative constructs, such as loops and catch filter clauses.
Use of this API is restricted to prevent misuse. This is critical since TryGetValue is essentially a function to get the value out of the option.
Allowed use cases
TryGetValue may be called anywhere inside
- the condition of a
while,doorforloop, - a
catchfilter clause (catch when (…)), - the condition of an
ifstatement in an iterator, if theifstatement (or itselsebranch) contains ayield returnoryield break.
The call has to belong to the same method, lambda or local function as the loop, filter or if statement. A call in a lambda that is
passed to a loop condition, such as while (items.Any(item => item.Option.TryGetValue(out _))), is not allowed.
Code in Razor components (.razor) and Razor pages and views (.cshtml) is exempt, since Razor's control flow constructs are not visible to the analyzer.
Taking a delegate to TryGetValue (Func<…> f = option.TryGetValue) is never allowed.
How to fix violations
Use one of the functions provided on Option<T> such as Select, SelectMany, Match or GetOrElse.
Examples
Disallowed
static void Example(Option<int> option)
{
const int fallback = 42;
var valueOrFallback = option.TryGetValue(out var value) ? value : fallback;
}
Allowed
Loop condition
public static IEnumerable<TItem> Successors<TItem>(Option<TItem> first, Func<TItem, Option<TItem>> successor)
where TItem : notnull
{
var item = first;
while (item.TryGetValue(out var itemValue))
{
yield return itemValue;
item = successor(itemValue);
}
}
Iterator
public static IEnumerable<TItem> ToEnumerable<TItem>(Option<TItem> option)
where TItem : notnull
{
if (option.TryGetValue(out var item))
{
yield return item;
}
}
Catch filter clause
try
{
// ...
} catch (Exception exception) when (FindHandlerForException(exception).TryGetValue(out var handler) && handler.CanHandle(exception))
{
handler.Handle(exception);
}
Option<IExceptionHandler> FindHandlerForException(Exception exception) => ...;