Having try-catch present in your code has a minimal, yet IMO neglectable performance cost: in the range of < 0.001 µs per 'try-that-didnt-catch' (using a .NET 4.6.1 Release build on my Core i7 x64 machine).
But if it has to catch, then it does cost quite a bit more: in the range of 12.5 µs per 'try-that-had-to-catch' (using a .NET 4.6.1 Release build on my Core i7 machine). Still you may not notice until you get to the level of 10s of thousands of caught exceptions.
All in all it is much better to avoid throwing-and-catching if you can, and you can do so here by using decimal.TryParse.
You now have to do null checking separately or else the .ToString()
might still crash it.
Rewritten code:
var v = dr[dc.ColumnName];
var s = v?.ToString(); // or you might use: var s = v as string;
if (s != null && decimal.TryParse(s, out decimal d))
cell.Value = d;
else
cell.Value = v;