File: ReflectionUtil.cs

package info (click to toggle)
mono 6.8.0.105%2Bdfsg-3.3
  • links: PTS, VCS
  • area: main
  • in suites: bookworm
  • size: 1,284,512 kB
  • sloc: cs: 11,172,132; xml: 2,850,069; ansic: 671,653; cpp: 122,091; perl: 59,366; javascript: 30,841; asm: 22,168; makefile: 20,093; sh: 15,020; python: 4,827; pascal: 925; sql: 859; sed: 16; php: 1
file content (69 lines) | stat: -rw-r--r-- 3,299 bytes parent folder | download | duplicates (7)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
//------------------------------------------------------------------------------
// <copyright file="ReflectionUtil.cs" company="Microsoft">
//     Copyright (c) Microsoft Corporation.  All rights reserved.
// </copyright>                                                                
//------------------------------------------------------------------------------

namespace System.Web.Util {
    using System;
    using System.Reflection;
    using System.Reflection.Emit;
    using System.Security.Permissions;

    // Provides helper methods for performing reflection over managed objects.

    [SecurityPermission(SecurityAction.LinkDemand, UnmanagedCode = true)]
    internal static class ReflectionUtil {

        // Resets an object to its "default" state, e.g. where each instance field is given the value default(TField).
        public static void Reset<T>(T obj) where T : class {
            ResetUtil<T>.ResetFn(obj);
        }

        private static class ResetUtil<T> where T : class {
            internal readonly static Action<T> ResetFn = CreateResetFn();

            private static Action<T> CreateResetFn() {
                Type targetType = typeof(T);
                DynamicMethod dynamicMethod = CreateDynamicMethodWithAssert();
                ILGenerator ilGen = dynamicMethod.GetILGenerator();

                // for each field in the target type, reset to default(TField)
                FieldInfo[] allFields = targetType.GetFields(BindingFlags.Instance | BindingFlags.DeclaredOnly | BindingFlags.NonPublic | BindingFlags.Public);
                foreach (FieldInfo fieldInfo in allFields) {
                    if (fieldInfo.IsInitOnly || fieldInfo.IsDefined(typeof(DoNotResetAttribute))) {
                        // This field is not eligible to be reset because it is marked readonly or [DoNotReset].
                        continue;
                    }

                    // obj.field = default(TField);
                    // Opcodes.Initobj can be used for both value and reference types; see ECMA 335, Partition III, Sec. 4.5 "initobj"
                    // (ref: http://www.ecma-international.org/publications/files/ECMA-ST/ECMA-335.pdf)
                    ilGen.Emit(OpCodes.Ldarg_0);
                    ilGen.Emit(OpCodes.Ldflda, fieldInfo);
                    ilGen.Emit(OpCodes.Initobj, fieldInfo.FieldType);
                }

                ilGen.Emit(OpCodes.Ret);
                // dynamicMethod = obj => {
                //   obj.field1 = default(TField1);
                //   obj.field2 = default(TField2);
                //   ...
                // };
                return (Action<T>)dynamicMethod.CreateDelegate(typeof(Action<T>));
            }

            [ReflectionPermission(SecurityAction.Assert, MemberAccess = true)] // needed to create a DynamicMethod inside the target type
            private static DynamicMethod CreateDynamicMethodWithAssert() {
                Type targetType = typeof(T);
                return new DynamicMethod(
                    name: "Reset-" + targetType.Name,
                    returnType: typeof(void),
                    parameterTypes: new Type[] { targetType },
                    owner: targetType,
                    skipVisibility: true);
            }
        }

    }
}