1 //------------------------------------------------------------------------------
2 // <copyright file="ReflectionUtil.cs" company="Microsoft">
3 // Copyright (c) Microsoft Corporation. All rights reserved.
5 //------------------------------------------------------------------------------
7 namespace System.Web.Util {
9 using System.Reflection;
10 using System.Reflection.Emit;
11 using System.Security.Permissions;
13 // Provides helper methods for performing reflection over managed objects.
15 [SecurityPermission(SecurityAction.LinkDemand, UnmanagedCode = true)]
16 internal static class ReflectionUtil {
18 // Resets an object to its "default" state, e.g. where each instance field is given the value default(TField).
19 public static void Reset<T>(T obj) where T : class {
20 ResetUtil<T>.ResetFn(obj);
23 private static class ResetUtil<T> where T : class {
24 internal readonly static Action<T> ResetFn = CreateResetFn();
26 private static Action<T> CreateResetFn() {
27 Type targetType = typeof(T);
28 DynamicMethod dynamicMethod = CreateDynamicMethodWithAssert();
29 ILGenerator ilGen = dynamicMethod.GetILGenerator();
31 // for each field in the target type, reset to default(TField)
32 FieldInfo[] allFields = targetType.GetFields(BindingFlags.Instance | BindingFlags.DeclaredOnly | BindingFlags.NonPublic | BindingFlags.Public);
33 foreach (FieldInfo fieldInfo in allFields) {
34 if (fieldInfo.IsInitOnly || fieldInfo.IsDefined(typeof(DoNotResetAttribute))) {
35 // This field is not eligible to be reset because it is marked readonly or [DoNotReset].
39 // obj.field = default(TField);
40 // Opcodes.Initobj can be used for both value and reference types; see ECMA 335, Partition III, Sec. 4.5 "initobj"
41 // (ref: http://www.ecma-international.org/publications/files/ECMA-ST/ECMA-335.pdf)
42 ilGen.Emit(OpCodes.Ldarg_0);
43 ilGen.Emit(OpCodes.Ldflda, fieldInfo);
44 ilGen.Emit(OpCodes.Initobj, fieldInfo.FieldType);
47 ilGen.Emit(OpCodes.Ret);
48 // dynamicMethod = obj => {
49 // obj.field1 = default(TField1);
50 // obj.field2 = default(TField2);
53 return (Action<T>)dynamicMethod.CreateDelegate(typeof(Action<T>));
56 [ReflectionPermission(SecurityAction.Assert, MemberAccess = true)] // needed to create a DynamicMethod inside the target type
57 private static DynamicMethod CreateDynamicMethodWithAssert() {
58 Type targetType = typeof(T);
59 return new DynamicMethod(
60 name: "Reset-" + targetType.Name,
61 returnType: typeof(void),
62 parameterTypes: new Type[] { targetType },
64 skipVisibility: true);