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) = PerlSetValueThis 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);
}
}1969What 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=PerlsMethodInfo, 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
GetTypeReflection 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 = HelloAssemblyThe 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
BoxIt 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.