Reflection Examples
This page was last reviewed on Jun 4, 2024.
Dot Net Perls
Reflection. A .NET program that uses reflection can examine it own surface—its fields, methods, types. Reflection is a powerful feature in C#, but it must be used with care.
With reflection, we usually have a significant performance loss—it is worthwhile to avoid using reflection in places where performance matters. Code that use this feature can be hard to maintain.
typeof, nameof
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.
Info In .NET a program is compiled into an assembly containing metadata. This is an abstract binary representation.
And We 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.
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(); } }
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.
Info 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
Argument 1 The first argument to SetValue() is the object instance you want to mutate. For a static field this can be left as null.
Argument 2 The second argument to SetValue is the value we want the object be have.
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); } }
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.
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 }); } } }
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.
Note 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.
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); } } } }
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).
Next We evaluate typeof(Program) and call GetProperties() on the Type returned. On the PropertyInfo type, we use Name and GetValue.
Return GetValue() returns an object. We use the is-cast to determine which we have, and then print custom messages to the Console.
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); } } } }
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.
Info 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.
Then The GetType method receives a string, and returns a Type pointer if one of that name is located.
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); } }
Box Program Box
Benchmark, reflection. 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.
Result The version that uses reflection to look up a field and set it is several hundred times slower.
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")); } }
161.84 ns GetField, SetValue 0.53 ns =
Summary. Programs that use reflection can look inside themselves to see their inner workings. This capacity lends them unique and powerful features.
Dot Net Perls is a collection of tested code examples. Pages are continually updated to stay current, with code correctness a top priority.
Sam Allen is passionate about computer languages. In the past, his work has been recommended by Apple and Microsoft and he has studied computers at a selective university in the United States.
This page was last updated on Jun 4, 2024 (simplify).
© 2007-2024 Sam Allen.