ContainsKey then the indexer is two searches.

The problem
Two searches for one answer.
if (scores.ContainsKey(name)){ var score = scores[name]; Show(score);}
ContainsKey hashes the key and walks the bucket. The indexer does the whole thing again.
The fix
Ask once, get both answers.
if (scores.TryGetValue(name, out var score)){ Show(score);}
TryGetValue returns whether it was there and hands you the value in the same lookup.
The same shape elsewhere
Most collections have a Try.
Any time you check then fetch, look for the paired call.
- Dictionary
- TryGetValue
- Queue and Stack
- TryDequeue, TryPop
- Parsing text
- int.TryParse
Each one replaces a check plus a fetch, or a try plus a catch.
The rule
Check and fetch is one call, not two.
- ContainsKey then []
- two lookups
- TryGetValue
- one lookup
- In a loop
- the difference doubles
out var declares it right there in the if.