HomeSearch

C# Reflection Examples

Learn about the System.Reflection namespace. Use FieldInfo, and call GetMethod and GetProperties.
Reflection. In the depths of the forest, a dark pool of water exists. It has almost no motion. It is a mirror. An animal (maybe a deer) sees it, but pays no attention.
In reflection, light is redirected. We see ourselves. A program that uses reflection can examine too it own surface—its fields, methods, types.
Fields. We loop through fields and display their names and values. System.Reflection provides a way to enumerate fields and properties. It can access fields by name.

Example: In the .NET Framework, every program is compiled into an assembly containing metadata. This is an abstract binary representation.

And: You can explore the string data stored in the executable to access field and property names.

Next: This static class has 4 fields of type Int32 and String. We get the FieldInfo objects for those fields and then display them.

StaticInt, uint
C# program that uses reflection on fields using System; using System.Reflection; static class ReflectionTest { public static int Height; public static int Width; public static int Weight; public static string Name; public static void Write() { Type type = typeof(ReflectionTest); // Obtain all fields with type pointer. FieldInfo[] fields = type.GetFields(); foreach (var field in fields) { string name = field.Name; object temp = field.GetValue(null); // See if it is an integer or string. if (temp is int) { int value = (int)temp; Console.Write(name); Console.Write(" (int) = "); Console.WriteLine(value); } else if (temp is string) { string value = temp as string; Console.Write(name); Console.Write(" (string) = "); Console.WriteLine(value); } } } } class Program { static void Main() { // Set values. ReflectionTest.Height = 100; ReflectionTest.Width = 50; ReflectionTest.Weight = 300; ReflectionTest.Name = "Perl"; // Invoke reflection methods. ReflectionTest.Write(); } } Output Height (int) = 100 Width (int) = 50 Weight (int) = 300 Name (string) = Perl
SetValue. This accesses fields by their names. With System.Reflection, we can take a string that represents a target field, and then change the actual value of that field.

First: This program has a public static int field with the identifier _field. We get the type of the class using the typeof operator.

Then: We call GetField with the string literal "_field" as the argument. We invoke the SetValue method.

String Literal

Note: The first argument to SetValue() is the object instance you want to mutate. For a static field this can be left as null.

Null
C# program that uses SetValue on FieldInfo using System; using System.Reflection; class Program { public static int _field; // Must be public! static void Main() { // Get FieldInfo on Program type. FieldInfo info = typeof(Program).GetField("_field"); // Set static field to this value. info.SetValue(null, 1969); // Now see what _field equals. Console.WriteLine(_field); } } Output 1969
Methods. What should we do if we have the name of a method in string format and want to call the method? We can use GetMethod. Then we invoke the MethodInfo we acquire from it.

Note: GetMethod references methods with only a string name. With it we call a method whose name equals this string.

Here: We want to call the Inform static method by using the string "Inform" and we want to call it twice with different parameters.

C# program that uses GetMethod using System; using System.Reflection; static class Methods { public static void Inform(string parameter) { Console.WriteLine("Inform:parameter={0}", parameter); } } class Program { static void Main() { // Name of the method we want to call. string name = "Inform"; // Call it with each of these parameters. string[] parameters = { "Sam", "Perls" }; // Get MethodInfo. Type type = typeof(Methods); MethodInfo info = type.GetMethod(name); // Loop over parameters. foreach (string parameter in parameters) { info.Invoke(null, new object[] { parameter }); } } } Output Inform:parameter=Sam Inform:parameter=Perls
MethodInfo, Invoke. An instance method can be called by its name. With the MethodInfo type, we call the Invoke method. We must provide an instance expression.

Example: GetMethods() on the Type class returns all the public instance methods on a type by default.

Here: We get an array of MethodInfo instances of all the public Program class methods.

And: We print their names, but also test for the Win method. If we find this method, we call Invoke on it.

C# program that calls Invoke on MethodInfo using System; using System.Reflection; class Program { public void Win() { Console.WriteLine("{You're a winner}"); } public void Lose() { } public void Draw() { } static void Main() { // Instance used for Invoke. Program program = new Program(); // Get methods. MethodInfo[] methods = typeof(Program).GetMethods(); foreach (MethodInfo info in methods) { Console.WriteLine(info.Name); // Call Win method. if (info.Name == "Win") { info.Invoke(program, null); } } } } Output Win {You're a winner} Lose Draw ToString Equals GetHashCode GetType
Reflection, properties. Reflection can get the values of properties. We loop over properties and determine their values. With reflection a property can be referenced by a string.

Start: The Program class has 2 instance properties: the Awesome property and the Perls property (sorry for the names).

Main: We evaluate typeof(Program) and call GetProperties() on the Type returned. On the PropertyInfo type, we use Name and GetValue.

GetValue: This requires the instance of the object we are searching. If you are using a static type, you can just pass null.

Casting: GetValue() returns an object. We use the is-cast to determine which we have, and then print custom messages to the Console.

IsConsole
C# program that uses reflection on properties using System; using System.Reflection; class Program { public int Awesome { get; set; } public string Perls { get; set; } static void Main() { // Create an instance of Program. Program programInstance = new Program(); programInstance.Awesome = 7; programInstance.Perls = "Hello"; // Get type. Type type = typeof(Program); // Loop over properties. foreach (PropertyInfo propertyInfo in type.GetProperties()) { // Get name. string name = propertyInfo.Name; // Get value on the target instance. object value = propertyInfo.GetValue(programInstance, null); // Test value type. if (value is int) { Console.WriteLine("Int: {0} = {1}", name, value); } else if (value is string) { Console.WriteLine("String: {0} = {1}", name, value); } } } } Output Int: Awesome = 7 String: Perls = Hello
Assembly. The Assembly type contains many Type instances. We can call GetCallingAssembly. And on Assembly, we can get an array of types, or a specific, named type.

Example: This file includes the System.Reflection namespace. We call Assembly.GetCallingAssembly() to get the current assembly.

And: With GetTypes, we receive an array of Type instances. We loop with foreach through these elements.

GetType: The GetType method next receives a string, and returns a Type pointer if one of that name is located.

C# program that uses Assembly type using System; using System.Reflection; class Box { } class Program { static void Main() { // Get assembly. Assembly assembly = Assembly.GetCallingAssembly(); // Get array of types. Type[] types = assembly.GetTypes(); foreach (Type t in types) { Console.WriteLine(t); } Console.WriteLine(); // Get type by name. string name = "Box"; Type type = assembly.GetType(name); Console.WriteLine(type); } } Output Box Program Box
Reflection performance. It is tempting to use reflection in places where it is not necessary. But this may come at a great performance cost.

Version 1: We use reflection (GetField, SetValue) to set the value of an integer property on the Program type.

Version 2: Use just as sign the value to the property directly in C# code. The performance is better in this version.

Info: The version that uses reflection to look up a field and set it is several hundred times slower.

C# program that tests reflection performance using System; using System.Diagnostics; using System.Reflection; class Program { public static int _field; const int _max = 1000000; static void Main() { // Version 1: use reflection to set field by name. var s1 = Stopwatch.StartNew(); for (int i = 0; i < _max; i++) { FieldInfo info = typeof(Program).GetField("_field"); info.SetValue(null, 1000); } s1.Stop(); // Version 2: set field directly. var s2 = Stopwatch.StartNew(); for (int i = 0; i < _max; i++) { _field = 1000; } s2.Stop(); Console.WriteLine(((double)(s1.Elapsed.TotalMilliseconds * 1000000) / _max).ToString("0.00 ns")); Console.WriteLine(((double)(s2.Elapsed.TotalMilliseconds * 1000000) / _max).ToString("0.00 ns")); } } Output 161.84 ns GetField, SetValue 0.53 ns =
Types. The "Type" type is important when reflecting. We cover the GetType method that is found on the object type. GetType helps us discover the object hierarchy.TypeGetType
Typeof. This operator uses reflection to return the Type of a variable. We use the typeof operator in most code that requires complicated reflection capabilities.Typeof, nameof
Sizeof. This operator exposes information about the implementation of types. It does not require the System.Reflection namespace. But it is related to reflection.Sizeof
Default. This operator returns the default value for a type. It is used when developing classes such as generics. The default value of an int is zero.Default
Discussion. Many programs must maintain a set of preference values that are assigned during startup or later execution. You can store these preferences in an array.

However: You can instead loop through fields with reflection and print their values to the console or web page.

Also: This approach improves performance when assigning or reading the values (because they are fields).

Field instructions. When you use fields (with stsfld or ldsfld) you are creating exception-free code. Reading fields, because it does not invoke executable code, will not throw exceptions.IL: stsfld, ldsfld
From .NET IL Assembler. "Structurally, metadata is a normalized relational database. This means that metadata is organized as a set of cross-referencing rectangular tables" (page 73).

Tip: When a C# program is compiled, it is converted into a relational database. When the runtime starts, it reads this program data.

A summary. Programs that use reflection can look inside themselves to see their inner workings. This capacity lends them unique and powerful features.
© 2007-2019 Sam Allen. Every person is special and unique. Send bug reports to info@dotnetperls.com.
Home
Dot Net Perls