Did you know that C# is actually quite good at manipulating types at runtime, too? That’s thanks to reflection! 🙂
This article is also available on Medium.
Reflection is an incredible tool that allows you to dynamically interact with your object types. Be it to create an object with a dynamically computed type, or to get the type of variable that is not knowable beforehand by the programmer, as is the case here, it is a very powerful feature that lets you write highly abstract code.
It’s a way of working with types that are not known at compile-time but at runtime.
I’ve had the chance to show various use cases for C# reflection in my on-going series of tutorials on how to make a RTS game in Unity/C#, so if you want “real-life” scenarios of using this tool in dev, make sure to check it out! 🙂 (For example, in episodes 17, 18 or 30)
And in the meantime, here are some util snippets using reflection in C# – I hope you’ll find them useful! 🙂
Snippet #1: Listing all the fields or properties of a class type
When you want to learn more about a class, reflection can tell you very useful like the set of fields or properties that it contains. This can be really cool for automating handmade serialisation or displaying basic info in an agnostic way, for example.
Suppose you have a very simple class like this one:
To list all the fields of this class type, you just need to get a reference to the type and then call the
GetFields() method on it:
But you’ll see that, by default,
GetFields() only searches for the public fields (here, I only get results for my two public variables). To also get the private ones, you have to pass in an additional parameter to your call: the binding flags.
This specific enumeration tells the reflection system how it should perform the search, and which types of members, properties, classes or fields should be included. The nice thing is that you can easily combine multiple flags using the “or bitwise operator”
// instance members BindingFlags.Instance // instance and static members BindingFlags.Instance | BindingFlags.Static // instance and private members BindingFlags.Instance | BindingFlags.NonPublic
Here is an example that lists all of the fields in our
TestClass (public, private and instance or static ones):
GetProperties() allows you to browse the properties of the class:
Snippet #2: Getting or setting a field value by field name
Sometimes, you want to access the field of an object by name instead of directly writing
.myField, either to get its current value or update it.
Let’s say we want to make a custom data save/load system that writes our objects in text files, with one field on each line. So, taking our
TestClass again as example, we could have something like this for a basic instance:
_myPrivateInt:5 _myPrivateString:hello world myPublicBool:true
Note: I’m ignoring the static float field because it does not depend on the instance but on the class 😉
Of course, in our case, we could implement this system with simple reads and assignments:
I’ve also added a
Print() method to easily get the current value of my fields and I can now test this: you see that I do retrieve my data properly! 🙂
But this is not very generic, and we are using a really ugly if-else block for loading back the data! If we change the fields in our class, this will crash unless we change both the save and load functions… and if we ever derive a new class from this
TestClass, we won’t have any way of saving and loading its specific fields!
To avoid these issues, we can use reflection to automatically list and save or retrieve the values, field per field.
The save function is straight-forward to write:
For the load, it’s a bit more tricky. That’s because we are reading strings from our file, so we have to implement a generic converter (that transforms a string into the corresponding value of the given type).
Here is an example of such a converter (from this Stack Overflow answer):
We can now call this converter in our
Load() function like this (the
MakeGenericMethod() is yet another reflection utility that allows you to call a generic function and pass in the generic type from a variable):
The nice thing is that I don’t have to change anything in my main routine because the interfaces haven’t changed, but the functions are now able to dynamically adapt if I change my fields, and I could even call the
Load() methods on derived-types without any issue!
Snippet #3: Calling a method by name
Just like, sometimes, you want to get a field value by name, it can also be interesting to get a reference to a method and call it using its string name as access key.
I’ve touched upon this in the previous section when I called the string converter – to get a method by name, you create a
MethodInfo variable using the
Suppose I have another simple class with some functions:
If I create an instance from this class, I can then use
GetMethod() to access its functions by name:
Once again, binding flags are important: by default, you only get public instance methods. To get a private or a static function you have to add flags to your
If I try and get a method that doesn’t exist, or that I use the wrong binding flags, I just get a null result:
Once you have accessed your
MethodInfo, to actually call the method, you need to use its
Invoke() function. It’s used differently for instance and static methods:
- for instance methods, you naturally have to pass in the instance to run the method on
- for static methods, on the other hand, you don’t need any instance so you can just pass in a
nullvalue for the instance
The second parameter is for input parameters, in case your method requires any. When you pass
null, you’re not sending any parameters; if you need to pass some, you’ll have to wrap them in an array of
- if you try to invoke a method that requires parameters without any, or vice-versa, you’ll get an error at runtime
- you can pass in an instance to
Invoke()for a static method if you want: it won’t be used but it won’t cause any error
Snippets #4/5: Listing classes in an assembly (+ filtering with Linq)
At a higher-level, it can be useful to know what classes are currently defined in your project. When searching for classes, you have to scope the search to a given assembly.
As explained in the Microsoft docs:
Assemblies form the fundamental units of deployment, version control, reuse, activation scoping, and security permissions for .NET-based applications. An assembly is a collection of types and resources that are built to work together and form a logical unit of functionality.
To list all the available classes in your assembly (meaning the assembly that the class you are calling this from resides in), you can use the
Assembly class from the reflection package. You usually combine it with a bit of Linq queries to isolate just the classes:
Of course, you can also look for a specific namespace or the classes derived from a type by adding more conditions to your Linq query:
I’ve only recently really dived into reflection in C# but I find that this tool is amazing: it allows me to get a deeper understanding of the relationships between my objects and it lets me write very abstract and generic code that is completely agnostic of the specifics 🙂
What about you – do you use reflection a lot in your C# projects? Have you had nice use cases for it? Don’t hesitate to react in the comments!