Just to be sure, MSIL is a beast in its own, but Reflection can roughly be seen on two levels:
1) Getting information about types,objects,methods and variables and also loading assemblies and getting information about assemblies.
2) Emitting code to dynamically create the above (and then some), during runtime.
Using Reflection can be very useful for the first scenario without having any knowledge about MSIL
As an example a bigger program may load modules only applicable to selected clients, a configuration file or a database field may specify which modules are relevant to the client. You can use reflection to dynamically load only the relevant modules for a client, the information (name of assembly, location of library/libraries etc.) about the assemblies need not be hardcoded hence somewhere else in the code it may be of importance which assemblies have been loaded alongside more information about them, again using Reflection.
Another example is passing objects of various types around, and not knowing which accessors (get/set methods they have), Reflection can give you that information and also invoke them, or on a different level checking the modifiers (eg. public/private/protected/internal) of methods in an object to check if you can pass the object somewhere and then be able to invoke those method in the target assembly for instance.