En termes simples : parce que parfois, vous ne connaissez pas les parties "Foo" ou "hello" au moment de la compilation.
La grande majorité du temps, vous faire le savent, donc ce n'est pas la peine d'utiliser la réflexion. Mais il arrive parfois que vous ne le sachiez pas, et à ce moment-là, la réflexion est tout ce que vous pouvez faire.
A titre d'exemple, tampons de protocole vous permet de générer du code qui contient soit du code complet typé statiquement pour la lecture et l'écriture des messages, soit juste assez pour que le reste puisse être fait par réflexion : dans le cas de la réflexion, le code de chargement/sauvegarde doit obtenir et définir les propriétés par réflexion - il connaît les noms des propriétés impliquées grâce au descripteur de message. Cette méthode est beaucoup plus lente, mais elle permet de générer beaucoup moins de code.
Un autre exemple serait l'injection de dépendances, où les noms des types utilisés pour les dépendances sont souvent fournis dans les fichiers de configuration : le cadre DI doit alors utiliser la réflexion pour construire tous les composants impliqués, en trouvant les constructeurs et/ou les propriétés en cours de route.