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.
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.
abstract
binary representation.string
data stored in the executable to access field and property names.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.
static
int
field with the identifier _field. We get the type of the class
using the typeof
operator.GetField
with the string
literal "_field" as the argument. We invoke the SetValue
method.SetValue()
is the object instance you want to mutate. For a static
field this can be left as null
.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); } }1969
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.
GetMethod
references methods with only a string
name. With it we call a method whose name equals this string
.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
, InvokeAn instance method can be called by its name. With the MethodInfo
type, we call the Invoke method. We must provide an instance expression.
GetMethods()
on the Type class
returns all the public instance methods on a type by default.MethodInfo
instances of all the public Program
class
methods.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 can get the values of properties. We loop over properties and determine their values. With reflection a property can be referenced by a string
.
Program
class
has 2 instance properties: the Awesome property and the Perls property (sorry for the names).typeof
(Program
) and call GetProperties()
on the Type returned. On the PropertyInfo
type, we use Name and GetValue
.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.
System.Reflection
namespace. We call Assembly.GetCallingAssembly()
to get the current assembly.GetTypes
, we receive an array of Type instances. We loop with foreach
through these elements.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
It is tempting to use reflection in places where it is not necessary. But this may come at a great performance cost.
GetField
, SetValue
) to set the value of an integer property on the Program
type.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 =
Programs that use reflection can look inside themselves to see their inner workings. This capacity lends them unique and powerful features.