Есть ли способ определить, был ли тип, которому был присвоен объект, динамическим типом?
Нет, если foo является локальной переменной.
«dynamic» - это функция времени компиляции. Это просто подсказка компилятору, которая означает «не пытайтесь выполнять анализ типов во время компиляции этого выражения; вместо этого генерируйте код, который вызывает специальную версию компилятора во время выполнения».
Во время выполнения локальная переменная foo является просто локальной переменной типа object, а содержимое локальной переменной является ссылкой на Cat. Тот факт, что компилятор знал, что автор кода хотел избежать анализа типов для foo во время компиляции, был утерян.
С помощью можно выяснить, действительно ли метод, возвращающий объект, возвращает динамический, изучив сгенерированные компилятором атрибуты метода, используя отражение.