├── .gitignore ├── Directory.Build.props ├── Mono.Reflection.csproj ├── Mono.Reflection.nuspec ├── Mono.Reflection.sln ├── Mono.Reflection ├── AssemblyInfo.cs ├── BackingFieldResolver.cs ├── ByteBuffer.cs ├── Disassembler.cs ├── ILPattern.cs ├── Image.cs ├── Instruction.cs └── MethodBodyReader.cs ├── README.md ├── Test ├── .gitignore ├── Mono.Reflection.Tests.csproj ├── Mono.Reflection │ ├── AssemblyInfo.cs │ ├── BackingFieldResolverTest.cs │ ├── BaseReflectionTest.cs │ ├── DisassemblerTest.cs │ ├── Formatter.cs │ └── ImageTest.cs ├── libs │ └── nunit-2.6.2 │ │ ├── license.txt │ │ ├── nunit.core.dll │ │ ├── nunit.core.interfaces.dll │ │ └── nunit.framework.dll ├── target.dll └── target.il └── mono.snk /.gitignore: -------------------------------------------------------------------------------- 1 | bin 2 | obj 3 | *.suo 4 | *.user 5 | *.nupkg 6 | *ReSharper* 7 | -------------------------------------------------------------------------------- /Directory.Build.props: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jbevain/mono.reflection/6f2c84705f0bf05baef3d7977a8c4b69843ed402/Directory.Build.props -------------------------------------------------------------------------------- /Mono.Reflection.csproj: -------------------------------------------------------------------------------- 1 | 2 | 3 | netstandard2.0;net40 4 | 5 | 6 | 7 | 8 | 9 | -------------------------------------------------------------------------------- /Mono.Reflection.nuspec: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | Mono.Reflection 5 | 2.0.0.0 6 | Mono.Reflection 7 | Jb Evain 8 | Jb Evain 9 | http://opensource.org/licenses/mit-license.php 10 | false 11 | http://github.com/jbevain/mono.reflection/ 12 | Complement for System.Reflection, including an IL disassembler. 13 | en-US 14 | assembly assemblies module modules il cil msil bytecode reflection disassembler 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | -------------------------------------------------------------------------------- /Mono.Reflection.sln: -------------------------------------------------------------------------------- 1 | Microsoft Visual Studio Solution File, Format Version 11.00 2 | # Visual Studio 2010 3 | Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Mono.Reflection", "Mono.Reflection.csproj", "{97B010AB-0756-46DC-B75A-7A6C4F6FF28D}" 4 | EndProject 5 | Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Mono.Reflection.Tests", "Test\Mono.Reflection.Tests.csproj", "{51FCE249-1187-46EC-96A6-E507889E700D}" 6 | EndProject 7 | Global 8 | GlobalSection(SolutionConfigurationPlatforms) = preSolution 9 | Debug|Any CPU = Debug|Any CPU 10 | Release|Any CPU = Release|Any CPU 11 | EndGlobalSection 12 | GlobalSection(ProjectConfigurationPlatforms) = postSolution 13 | {97B010AB-0756-46DC-B75A-7A6C4F6FF28D}.Debug|Any CPU.ActiveCfg = Debug|Any CPU 14 | {97B010AB-0756-46DC-B75A-7A6C4F6FF28D}.Debug|Any CPU.Build.0 = Debug|Any CPU 15 | {97B010AB-0756-46DC-B75A-7A6C4F6FF28D}.Release|Any CPU.ActiveCfg = Release|Any CPU 16 | {97B010AB-0756-46DC-B75A-7A6C4F6FF28D}.Release|Any CPU.Build.0 = Release|Any CPU 17 | {51FCE249-1187-46EC-96A6-E507889E700D}.Debug|Any CPU.ActiveCfg = Debug|Any CPU 18 | {51FCE249-1187-46EC-96A6-E507889E700D}.Debug|Any CPU.Build.0 = Debug|Any CPU 19 | {51FCE249-1187-46EC-96A6-E507889E700D}.Release|Any CPU.ActiveCfg = Release|Any CPU 20 | {51FCE249-1187-46EC-96A6-E507889E700D}.Release|Any CPU.Build.0 = Release|Any CPU 21 | EndGlobalSection 22 | GlobalSection(SolutionProperties) = preSolution 23 | HideSolutionNode = FALSE 24 | EndGlobalSection 25 | EndGlobal 26 | -------------------------------------------------------------------------------- /Mono.Reflection/AssemblyInfo.cs: -------------------------------------------------------------------------------- 1 | using System.Reflection; 2 | using System.Runtime.CompilerServices; 3 | using System.Runtime.InteropServices; 4 | 5 | [assembly: AssemblyTitle ("Mono.Reflection")] 6 | [assembly: AssemblyDescription ("")] 7 | [assembly: AssemblyConfiguration ("")] 8 | [assembly: AssemblyCompany ("Novell, Inc.")] 9 | [assembly: AssemblyProduct ("Mono.Reflection")] 10 | [assembly: AssemblyCopyright ("Copyright © Novell, Inc. 2009 - 2010")] 11 | [assembly: AssemblyTrademark ("")] 12 | [assembly: AssemblyCulture ("")] 13 | 14 | [assembly: ComVisible (false)] 15 | 16 | [assembly: Guid ("61b023e8-6ba6-4fa3-8026-3841abdba125")] 17 | 18 | [assembly: AssemblyVersion ("2.0.0.0")] 19 | [assembly: AssemblyFileVersion ("2.0.0.0")] 20 | -------------------------------------------------------------------------------- /Mono.Reflection/BackingFieldResolver.cs: -------------------------------------------------------------------------------- 1 | // 2 | // BackingFieldResolver.cs 3 | // 4 | // Author: 5 | // Jb Evain (jbevain@novell.com) 6 | // 7 | // (C) 2009 - 2010 Novell, Inc. (http://www.novell.com) 8 | // 9 | // Permission is hereby granted, free of charge, to any person obtaining 10 | // a copy of this software and associated documentation files (the 11 | // "Software"), to deal in the Software without restriction, including 12 | // without limitation the rights to use, copy, modify, merge, publish, 13 | // distribute, sublicense, and/or sell copies of the Software, and to 14 | // permit persons to whom the Software is furnished to do so, subject to 15 | // the following conditions: 16 | // 17 | // The above copyright notice and this permission notice shall be 18 | // included in all copies or substantial portions of the Software. 19 | // 20 | // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, 21 | // EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF 22 | // MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND 23 | // NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE 24 | // LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION 25 | // OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION 26 | // WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. 27 | // 28 | 29 | using System; 30 | using System.Reflection; 31 | using System.Reflection.Emit; 32 | 33 | namespace Mono.Reflection { 34 | 35 | public static class BackingFieldResolver { 36 | 37 | class FieldPattern : ILPattern { 38 | 39 | public static object FieldKey = new object (); 40 | 41 | ILPattern pattern; 42 | 43 | public FieldPattern (ILPattern pattern) 44 | { 45 | this.pattern = pattern; 46 | } 47 | 48 | public override void Match (MatchContext context) 49 | { 50 | pattern.Match (context); 51 | if (!context.success) 52 | return; 53 | 54 | var match = GetLastMatchingInstruction (context); 55 | var field = (FieldInfo) match.Operand; 56 | context.AddData (FieldKey, field); 57 | } 58 | } 59 | 60 | static ILPattern Field (OpCode opcode) 61 | { 62 | return new FieldPattern (ILPattern.OpCode (opcode)); 63 | } 64 | 65 | static ILPattern GetterPattern = 66 | ILPattern.Sequence ( 67 | ILPattern.Optional (OpCodes.Nop), 68 | ILPattern.Either ( 69 | Field (OpCodes.Ldsfld), 70 | ILPattern.Sequence ( 71 | ILPattern.OpCode (OpCodes.Ldarg_0), 72 | Field (OpCodes.Ldfld))), 73 | ILPattern.Optional ( 74 | ILPattern.Sequence ( 75 | ILPattern.OpCode (OpCodes.Stloc_0), 76 | ILPattern.OpCode (OpCodes.Br_S), 77 | ILPattern.OpCode (OpCodes.Ldloc_0))), 78 | ILPattern.Optional(ILPattern.OpCode(OpCodes.Br_S)), 79 | ILPattern.OpCode (OpCodes.Ret)); 80 | 81 | static ILPattern SetterPattern = 82 | ILPattern.Sequence ( 83 | ILPattern.Optional (OpCodes.Nop), 84 | ILPattern.OpCode (OpCodes.Ldarg_0), 85 | ILPattern.Either ( 86 | Field (OpCodes.Stsfld), 87 | ILPattern.Sequence ( 88 | ILPattern.OpCode (OpCodes.Ldarg_1), 89 | Field (OpCodes.Stfld))), 90 | ILPattern.OpCode (OpCodes.Ret)); 91 | 92 | static FieldInfo GetBackingField (MethodInfo method, ILPattern pattern) 93 | { 94 | var result = ILPattern.Match (method, pattern); 95 | if (!result.success) 96 | throw new ArgumentException (); 97 | 98 | object value; 99 | if (!result.TryGetData (FieldPattern.FieldKey, out value)) 100 | throw new InvalidOperationException (); 101 | 102 | return (FieldInfo) value; 103 | } 104 | 105 | public static FieldInfo GetBackingField (this PropertyInfo self) 106 | { 107 | if (self == null) 108 | throw new ArgumentNullException ("self"); 109 | 110 | var getter = self.GetGetMethod (true); 111 | if (getter != null) 112 | return GetBackingField (getter, GetterPattern); 113 | 114 | var setter = self.GetSetMethod (true); 115 | if (setter != null) 116 | return GetBackingField (setter, SetterPattern); 117 | 118 | throw new ArgumentException (); 119 | } 120 | } 121 | } 122 | -------------------------------------------------------------------------------- /Mono.Reflection/ByteBuffer.cs: -------------------------------------------------------------------------------- 1 | // 2 | // ByteBuffer.cs 3 | // 4 | // Author: 5 | // Jb Evain (jbevain@novell.com) 6 | // 7 | // (C) 2009 - 2010 Novell, Inc. (http://www.novell.com) 8 | // 9 | // Permission is hereby granted, free of charge, to any person obtaining 10 | // a copy of this software and associated documentation files (the 11 | // "Software"), to deal in the Software without restriction, including 12 | // without limitation the rights to use, copy, modify, merge, publish, 13 | // distribute, sublicense, and/or sell copies of the Software, and to 14 | // permit persons to whom the Software is furnished to do so, subject to 15 | // the following conditions: 16 | // 17 | // The above copyright notice and this permission notice shall be 18 | // included in all copies or substantial portions of the Software. 19 | // 20 | // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, 21 | // EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF 22 | // MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND 23 | // NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE 24 | // LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION 25 | // OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION 26 | // WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. 27 | // 28 | 29 | using System; 30 | 31 | namespace Mono.Reflection { 32 | 33 | class ByteBuffer { 34 | 35 | internal byte [] buffer; 36 | internal int position; 37 | 38 | public ByteBuffer (byte [] buffer) 39 | { 40 | this.buffer = buffer; 41 | } 42 | 43 | public byte ReadByte () 44 | { 45 | CheckCanRead (1); 46 | return buffer [position++]; 47 | } 48 | 49 | public byte [] ReadBytes (int length) 50 | { 51 | CheckCanRead (length); 52 | var value = new byte [length]; 53 | Buffer.BlockCopy (buffer, position, value, 0, length); 54 | position += length; 55 | return value; 56 | } 57 | 58 | public short ReadInt16 () 59 | { 60 | CheckCanRead (2); 61 | short value = (short) (buffer [position] 62 | | (buffer [position + 1] << 8)); 63 | position += 2; 64 | return value; 65 | } 66 | 67 | public int ReadInt32 () 68 | { 69 | CheckCanRead (4); 70 | int value = buffer [position] 71 | | (buffer [position + 1] << 8) 72 | | (buffer [position + 2] << 16) 73 | | (buffer [position + 3] << 24); 74 | position += 4; 75 | return value; 76 | } 77 | 78 | public long ReadInt64 () 79 | { 80 | CheckCanRead (8); 81 | uint low = (uint) (buffer [position] 82 | | (buffer [position + 1] << 8) 83 | | (buffer [position + 2] << 16) 84 | | (buffer [position + 3] << 24)); 85 | 86 | uint high = (uint) (buffer [position + 4] 87 | | (buffer [position + 5] << 8) 88 | | (buffer [position + 6] << 16) 89 | | (buffer [position + 7] << 24)); 90 | 91 | long value = (((long) high) << 32) | low; 92 | position += 8; 93 | return value; 94 | } 95 | 96 | public float ReadSingle () 97 | { 98 | if (!BitConverter.IsLittleEndian) { 99 | var bytes = ReadBytes (4); 100 | Array.Reverse (bytes); 101 | return BitConverter.ToSingle (bytes, 0); 102 | } 103 | 104 | CheckCanRead (4); 105 | float value = BitConverter.ToSingle (buffer, position); 106 | position += 4; 107 | return value; 108 | } 109 | 110 | public double ReadDouble () 111 | { 112 | if (!BitConverter.IsLittleEndian) { 113 | var bytes = ReadBytes (8); 114 | Array.Reverse (bytes); 115 | return BitConverter.ToDouble (bytes, 0); 116 | } 117 | 118 | CheckCanRead (8); 119 | double value = BitConverter.ToDouble (buffer, position); 120 | position += 8; 121 | return value; 122 | } 123 | 124 | void CheckCanRead (int count) 125 | { 126 | if (position + count > buffer.Length) 127 | throw new ArgumentOutOfRangeException (); 128 | } 129 | } 130 | } 131 | -------------------------------------------------------------------------------- /Mono.Reflection/Disassembler.cs: -------------------------------------------------------------------------------- 1 | // 2 | // Disassembler.cs 3 | // 4 | // Author: 5 | // Jb Evain (jbevain@novell.com) 6 | // 7 | // (C) 2009 - 2010 Novell, Inc. (http://www.novell.com) 8 | // 9 | // Permission is hereby granted, free of charge, to any person obtaining 10 | // a copy of this software and associated documentation files (the 11 | // "Software"), to deal in the Software without restriction, including 12 | // without limitation the rights to use, copy, modify, merge, publish, 13 | // distribute, sublicense, and/or sell copies of the Software, and to 14 | // permit persons to whom the Software is furnished to do so, subject to 15 | // the following conditions: 16 | // 17 | // The above copyright notice and this permission notice shall be 18 | // included in all copies or substantial portions of the Software. 19 | // 20 | // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, 21 | // EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF 22 | // MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND 23 | // NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE 24 | // LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION 25 | // OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION 26 | // WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. 27 | // 28 | 29 | using System; 30 | using System.Collections.Generic; 31 | using System.Reflection; 32 | 33 | namespace Mono.Reflection { 34 | 35 | public static class Disassembler { 36 | 37 | public static IList GetInstructions (this MethodBase self) 38 | { 39 | if (self == null) 40 | throw new ArgumentNullException ("self"); 41 | 42 | return MethodBodyReader.GetInstructions (self).AsReadOnly (); 43 | } 44 | } 45 | } 46 | -------------------------------------------------------------------------------- /Mono.Reflection/ILPattern.cs: -------------------------------------------------------------------------------- 1 | // 2 | // ILPattern.cs 3 | // 4 | // Author: 5 | // Jb Evain (jbevain@novell.com) 6 | // 7 | // (C) 2009 - 2010 Novell, Inc. (http://www.novell.com) 8 | // 9 | // Permission is hereby granted, free of charge, to any person obtaining 10 | // a copy of this software and associated documentation files (the 11 | // "Software"), to deal in the Software without restriction, including 12 | // without limitation the rights to use, copy, modify, merge, publish, 13 | // distribute, sublicense, and/or sell copies of the Software, and to 14 | // permit persons to whom the Software is furnished to do so, subject to 15 | // the following conditions: 16 | // 17 | // The above copyright notice and this permission notice shall be 18 | // included in all copies or substantial portions of the Software. 19 | // 20 | // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, 21 | // EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF 22 | // MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND 23 | // NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE 24 | // LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION 25 | // OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION 26 | // WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. 27 | // 28 | 29 | using System; 30 | using System.Collections.Generic; 31 | using System.Linq; 32 | using System.Reflection; 33 | using System.Reflection.Emit; 34 | 35 | namespace Mono.Reflection { 36 | 37 | public abstract class ILPattern { 38 | 39 | public static ILPattern Optional (OpCode opcode) 40 | { 41 | return Optional (OpCode (opcode)); 42 | } 43 | 44 | public static ILPattern Optional (params OpCode [] opcodes) 45 | { 46 | return Optional (Sequence (opcodes.Select (opcode => OpCode (opcode)).ToArray ())); 47 | } 48 | 49 | public static ILPattern Optional (ILPattern pattern) 50 | { 51 | return new OptionalPattern (pattern); 52 | } 53 | 54 | class OptionalPattern : ILPattern { 55 | 56 | ILPattern pattern; 57 | 58 | public OptionalPattern (ILPattern optional) 59 | { 60 | this.pattern = optional; 61 | } 62 | 63 | public override void Match (MatchContext context) 64 | { 65 | pattern.TryMatch (context); 66 | } 67 | } 68 | 69 | public static ILPattern Sequence (params ILPattern [] patterns) 70 | { 71 | return new SequencePattern (patterns); 72 | } 73 | 74 | class SequencePattern : ILPattern { 75 | 76 | ILPattern [] patterns; 77 | 78 | public SequencePattern (ILPattern [] patterns) 79 | { 80 | this.patterns = patterns; 81 | } 82 | 83 | public override void Match (MatchContext context) 84 | { 85 | foreach (var pattern in patterns) { 86 | pattern.Match (context); 87 | 88 | if (!context.success) 89 | break; 90 | } 91 | } 92 | } 93 | 94 | public static ILPattern OpCode (OpCode opcode) 95 | { 96 | return new OpCodePattern (opcode); 97 | } 98 | 99 | class OpCodePattern : ILPattern { 100 | 101 | OpCode opcode; 102 | 103 | public OpCodePattern (OpCode opcode) 104 | { 105 | this.opcode = opcode; 106 | } 107 | 108 | public override void Match (MatchContext context) 109 | { 110 | if (context.instruction == null) { 111 | context.success = false; 112 | return; 113 | } 114 | 115 | context.success = context.instruction.OpCode == opcode; 116 | context.Advance (); 117 | } 118 | } 119 | 120 | public static ILPattern Either (ILPattern a, ILPattern b) 121 | { 122 | return new EitherPattern (a, b); 123 | } 124 | 125 | class EitherPattern : ILPattern { 126 | 127 | ILPattern a; 128 | ILPattern b; 129 | 130 | public EitherPattern (ILPattern a, ILPattern b) 131 | { 132 | this.a = a; 133 | this.b = b; 134 | } 135 | 136 | public override void Match (MatchContext context) 137 | { 138 | if (!a.TryMatch (context)) 139 | b.Match (context); 140 | } 141 | } 142 | 143 | public abstract void Match (MatchContext context); 144 | 145 | protected static Instruction GetLastMatchingInstruction (MatchContext context) 146 | { 147 | if (context.instruction == null) 148 | return null; 149 | 150 | return context.instruction.Previous; 151 | } 152 | 153 | public bool TryMatch (MatchContext context) 154 | { 155 | var instruction = context.instruction; 156 | Match (context); 157 | 158 | if (context.success) 159 | return true; 160 | 161 | context.Reset (instruction); 162 | return false; 163 | } 164 | 165 | public static MatchContext Match (MethodBase method, ILPattern pattern) 166 | { 167 | if (method == null) 168 | throw new ArgumentNullException ("method"); 169 | if (pattern == null) 170 | throw new ArgumentNullException ("pattern"); 171 | 172 | var instructions = method.GetInstructions (); 173 | if (instructions.Count == 0) 174 | throw new ArgumentException (); 175 | 176 | var context = new MatchContext (instructions [0]); 177 | pattern.Match (context); 178 | return context; 179 | } 180 | } 181 | 182 | public sealed class MatchContext { 183 | 184 | internal Instruction instruction; 185 | internal bool success; 186 | 187 | Dictionary data = new Dictionary (); 188 | 189 | public bool IsMatch { 190 | get { return success; } 191 | set { success = true; } 192 | } 193 | 194 | internal MatchContext (Instruction instruction) 195 | { 196 | Reset (instruction); 197 | } 198 | 199 | public bool TryGetData (object key, out object value) 200 | { 201 | return data.TryGetValue (key, out value); 202 | } 203 | 204 | public void AddData (object key, object value) 205 | { 206 | data.Add (key, value); 207 | } 208 | 209 | internal void Reset (Instruction instruction) 210 | { 211 | this.instruction = instruction; 212 | this.success = true; 213 | } 214 | 215 | internal void Advance () 216 | { 217 | this.instruction = this.instruction.Next; 218 | } 219 | } 220 | } 221 | -------------------------------------------------------------------------------- /Mono.Reflection/Image.cs: -------------------------------------------------------------------------------- 1 | // 2 | // Image.cs 3 | // 4 | // Author: 5 | // Jb Evain (jbevain@novell.com) 6 | // 7 | // (C) 2009 - 2010 Novell, Inc. (http://www.novell.com) 8 | // 9 | // Permission is hereby granted, free of charge, to any person obtaining 10 | // a copy of this software and associated documentation files (the 11 | // "Software"), to deal in the Software without restriction, including 12 | // without limitation the rights to use, copy, modify, merge, publish, 13 | // distribute, sublicense, and/or sell copies of the Software, and to 14 | // permit persons to whom the Software is furnished to do so, subject to 15 | // the following conditions: 16 | // 17 | // The above copyright notice and this permission notice shall be 18 | // included in all copies or substantial portions of the Software. 19 | // 20 | // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, 21 | // EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF 22 | // MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND 23 | // NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE 24 | // LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION 25 | // OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION 26 | // WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. 27 | // 28 | 29 | using System; 30 | using System.IO; 31 | 32 | namespace Mono.Reflection { 33 | 34 | public sealed class Image : IDisposable { 35 | 36 | long position; 37 | Stream stream; 38 | 39 | Image (Stream stream) 40 | { 41 | this.stream = stream; 42 | this.position = stream.Position; 43 | this.stream.Position = 0; 44 | } 45 | 46 | bool Advance (int length) 47 | { 48 | if (stream.Position + length >= stream.Length) 49 | return false; 50 | 51 | stream.Seek (length, SeekOrigin.Current); 52 | return true; 53 | } 54 | 55 | bool MoveTo (uint position) 56 | { 57 | if (position >= stream.Length) 58 | return false; 59 | 60 | stream.Position = position; 61 | return true; 62 | } 63 | 64 | void IDisposable.Dispose () 65 | { 66 | stream.Position = position; 67 | } 68 | 69 | ushort ReadUInt16 () 70 | { 71 | return (ushort) (stream.ReadByte () 72 | | (stream.ReadByte () << 8)); 73 | } 74 | 75 | uint ReadUInt32 () 76 | { 77 | return (uint) (stream.ReadByte () 78 | | (stream.ReadByte () << 8) 79 | | (stream.ReadByte () << 16) 80 | | (stream.ReadByte () << 24)); 81 | } 82 | 83 | bool IsManagedAssembly () 84 | { 85 | if (stream.Length < 318) 86 | return false; 87 | if (ReadUInt16 () != 0x5a4d) 88 | return false; 89 | if (!Advance (58)) 90 | return false; 91 | if (!MoveTo (ReadUInt32 ())) 92 | return false; 93 | if (ReadUInt32 () != 0x00004550) 94 | return false; 95 | if (!Advance (20)) 96 | return false; 97 | if (!Advance (ReadUInt16 () == 0x20b ? 222 : 206)) 98 | return false; 99 | 100 | return ReadUInt32 () != 0; 101 | } 102 | 103 | public static bool IsAssembly (string file) 104 | { 105 | if (file == null) 106 | throw new ArgumentNullException ("file"); 107 | 108 | using (var stream = new FileStream (file, FileMode.Open, FileAccess.Read, FileShare.Read)) 109 | return IsAssembly (stream); 110 | } 111 | 112 | public static bool IsAssembly (Stream stream) 113 | { 114 | if (stream == null) 115 | throw new ArgumentNullException ("stream"); 116 | if (!stream.CanRead) 117 | throw new ArgumentException ("Can not read from stream"); 118 | if (!stream.CanSeek) 119 | throw new ArgumentException ("Can not seek in stream"); 120 | 121 | using (var image = new Image (stream)) 122 | return image.IsManagedAssembly (); 123 | } 124 | } 125 | } 126 | -------------------------------------------------------------------------------- /Mono.Reflection/Instruction.cs: -------------------------------------------------------------------------------- 1 | // 2 | // Instruction.cs 3 | // 4 | // Author: 5 | // Jb Evain (jbevain@novell.com) 6 | // 7 | // (C) 2009 - 2010 Novell, Inc. (http://www.novell.com) 8 | // 9 | // Permission is hereby granted, free of charge, to any person obtaining 10 | // a copy of this software and associated documentation files (the 11 | // "Software"), to deal in the Software without restriction, including 12 | // without limitation the rights to use, copy, modify, merge, publish, 13 | // distribute, sublicense, and/or sell copies of the Software, and to 14 | // permit persons to whom the Software is furnished to do so, subject to 15 | // the following conditions: 16 | // 17 | // The above copyright notice and this permission notice shall be 18 | // included in all copies or substantial portions of the Software. 19 | // 20 | // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, 21 | // EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF 22 | // MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND 23 | // NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE 24 | // LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION 25 | // OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION 26 | // WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. 27 | // 28 | 29 | using System; 30 | using System.Reflection.Emit; 31 | using System.Text; 32 | 33 | namespace Mono.Reflection { 34 | 35 | public sealed class Instruction { 36 | 37 | int offset; 38 | OpCode opcode; 39 | object operand; 40 | 41 | Instruction previous; 42 | Instruction next; 43 | 44 | public int Offset { 45 | get { return offset; } 46 | } 47 | 48 | public OpCode OpCode { 49 | get { return opcode; } 50 | } 51 | 52 | public object Operand { 53 | get { return operand; } 54 | internal set { operand = value; } 55 | } 56 | 57 | public Instruction Previous { 58 | get { return previous; } 59 | internal set { previous = value; } 60 | } 61 | 62 | public Instruction Next { 63 | get { return next; } 64 | internal set { next = value; } 65 | } 66 | 67 | public int Size { 68 | get { 69 | int size = opcode.Size; 70 | 71 | switch (opcode.OperandType) { 72 | case OperandType.InlineSwitch: 73 | size += (1 + ((Instruction []) operand).Length) * 4; 74 | break; 75 | case OperandType.InlineI8: 76 | case OperandType.InlineR: 77 | size += 8; 78 | break; 79 | case OperandType.InlineBrTarget: 80 | case OperandType.InlineField: 81 | case OperandType.InlineI: 82 | case OperandType.InlineMethod: 83 | case OperandType.InlineString: 84 | case OperandType.InlineTok: 85 | case OperandType.InlineType: 86 | case OperandType.ShortInlineR: 87 | size += 4; 88 | break; 89 | case OperandType.InlineVar: 90 | size += 2; 91 | break; 92 | case OperandType.ShortInlineBrTarget: 93 | case OperandType.ShortInlineI: 94 | case OperandType.ShortInlineVar: 95 | size += 1; 96 | break; 97 | } 98 | 99 | return size; 100 | } 101 | } 102 | 103 | internal Instruction (int offset, OpCode opcode) 104 | { 105 | this.offset = offset; 106 | this.opcode = opcode; 107 | } 108 | 109 | public override string ToString () 110 | { 111 | var instruction = new StringBuilder (); 112 | 113 | AppendLabel (instruction, this); 114 | instruction.Append (':'); 115 | instruction.Append (' '); 116 | instruction.Append (opcode.Name); 117 | 118 | if (operand == null) 119 | return instruction.ToString (); 120 | 121 | instruction.Append (' '); 122 | 123 | switch (opcode.OperandType) { 124 | case OperandType.ShortInlineBrTarget: 125 | case OperandType.InlineBrTarget: 126 | AppendLabel (instruction, (Instruction) operand); 127 | break; 128 | case OperandType.InlineSwitch: 129 | var labels = (Instruction []) operand; 130 | for (int i = 0; i < labels.Length; i++) { 131 | if (i > 0) 132 | instruction.Append (','); 133 | 134 | AppendLabel (instruction, labels [i]); 135 | } 136 | break; 137 | case OperandType.InlineString: 138 | instruction.Append ('\"'); 139 | instruction.Append (operand); 140 | instruction.Append ('\"'); 141 | break; 142 | default: 143 | instruction.Append (operand); 144 | break; 145 | } 146 | 147 | return instruction.ToString (); 148 | } 149 | 150 | static void AppendLabel (StringBuilder builder, Instruction instruction) 151 | { 152 | builder.Append ("IL_"); 153 | builder.Append (instruction.offset.ToString ("x4")); 154 | } 155 | } 156 | } 157 | -------------------------------------------------------------------------------- /Mono.Reflection/MethodBodyReader.cs: -------------------------------------------------------------------------------- 1 | // 2 | // MethodBodyReader.cs 3 | // 4 | // Author: 5 | // Jb Evain (jbevain@novell.com) 6 | // 7 | // (C) 2009 - 2010 Novell, Inc. (http://www.novell.com) 8 | // 9 | // Permission is hereby granted, free of charge, to any person obtaining 10 | // a copy of this software and associated documentation files (the 11 | // "Software"), to deal in the Software without restriction, including 12 | // without limitation the rights to use, copy, modify, merge, publish, 13 | // distribute, sublicense, and/or sell copies of the Software, and to 14 | // permit persons to whom the Software is furnished to do so, subject to 15 | // the following conditions: 16 | // 17 | // The above copyright notice and this permission notice shall be 18 | // included in all copies or substantial portions of the Software. 19 | // 20 | // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, 21 | // EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF 22 | // MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND 23 | // NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE 24 | // LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION 25 | // OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION 26 | // WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. 27 | // 28 | 29 | using System; 30 | using System.Collections.Generic; 31 | using System.Reflection; 32 | using System.Reflection.Emit; 33 | 34 | namespace Mono.Reflection { 35 | 36 | class MethodBodyReader { 37 | 38 | static readonly OpCode [] one_byte_opcodes; 39 | static readonly OpCode [] two_bytes_opcodes; 40 | 41 | static MethodBodyReader () 42 | { 43 | one_byte_opcodes = new OpCode [0xe1]; 44 | two_bytes_opcodes = new OpCode [0x1f]; 45 | 46 | var fields = typeof (OpCodes).GetFields ( 47 | BindingFlags.Public | BindingFlags.Static); 48 | 49 | foreach (var field in fields) { 50 | var opcode = (OpCode) field.GetValue (null); 51 | if (opcode.OpCodeType == OpCodeType.Nternal) 52 | continue; 53 | 54 | if (opcode.Size == 1) 55 | one_byte_opcodes [opcode.Value] = opcode; 56 | else 57 | two_bytes_opcodes [opcode.Value & 0xff] = opcode; 58 | } 59 | } 60 | 61 | readonly MethodBase method; 62 | readonly MethodBody body; 63 | readonly Module module; 64 | readonly Type [] type_arguments; 65 | readonly Type [] method_arguments; 66 | readonly ByteBuffer il; 67 | readonly ParameterInfo this_parameter; 68 | readonly ParameterInfo [] parameters; 69 | readonly IList locals; 70 | readonly List instructions; 71 | 72 | MethodBodyReader (MethodBase method) 73 | { 74 | this.method = method; 75 | 76 | this.body = method.GetMethodBody (); 77 | if (this.body == null) 78 | throw new ArgumentException ("Method has no body"); 79 | 80 | var bytes = body.GetILAsByteArray (); 81 | if (bytes == null) 82 | throw new ArgumentException ("Can not get the body of the method"); 83 | 84 | if (!(method is ConstructorInfo)) 85 | method_arguments = method.GetGenericArguments (); 86 | 87 | if (method.DeclaringType != null) 88 | type_arguments = method.DeclaringType.GetGenericArguments (); 89 | 90 | if (!method.IsStatic) 91 | this.this_parameter = new ThisParameter (method); 92 | this.parameters = method.GetParameters (); 93 | this.locals = body.LocalVariables; 94 | this.module = method.Module; 95 | this.il = new ByteBuffer (bytes); 96 | this.instructions = new List ((bytes.Length + 1) / 2); 97 | } 98 | 99 | void ReadInstructions () 100 | { 101 | Instruction previous = null; 102 | 103 | while (il.position < il.buffer.Length) { 104 | var instruction = new Instruction (il.position, ReadOpCode ()); 105 | 106 | ReadOperand (instruction); 107 | 108 | if (previous != null) { 109 | instruction.Previous = previous; 110 | previous.Next = instruction; 111 | } 112 | 113 | instructions.Add (instruction); 114 | previous = instruction; 115 | } 116 | 117 | ResolveBranches (); 118 | } 119 | 120 | void ReadOperand (Instruction instruction) 121 | { 122 | switch (instruction.OpCode.OperandType) { 123 | case OperandType.InlineNone: 124 | break; 125 | case OperandType.InlineSwitch: 126 | int length = il.ReadInt32 (); 127 | int base_offset = il.position + (4 * length); 128 | int [] branches = new int [length]; 129 | for (int i = 0; i < length; i++) 130 | branches [i] = il.ReadInt32 () + base_offset; 131 | 132 | instruction.Operand = branches; 133 | break; 134 | case OperandType.ShortInlineBrTarget: 135 | instruction.Operand = (((sbyte) il.ReadByte ()) + il.position); 136 | break; 137 | case OperandType.InlineBrTarget: 138 | instruction.Operand = il.ReadInt32 () + il.position; 139 | break; 140 | case OperandType.ShortInlineI: 141 | if (instruction.OpCode == OpCodes.Ldc_I4_S) 142 | instruction.Operand = (sbyte) il.ReadByte (); 143 | else 144 | instruction.Operand = il.ReadByte (); 145 | break; 146 | case OperandType.InlineI: 147 | instruction.Operand = il.ReadInt32 (); 148 | break; 149 | case OperandType.ShortInlineR: 150 | instruction.Operand = il.ReadSingle (); 151 | break; 152 | case OperandType.InlineR: 153 | instruction.Operand = il.ReadDouble (); 154 | break; 155 | case OperandType.InlineI8: 156 | instruction.Operand = il.ReadInt64 (); 157 | break; 158 | case OperandType.InlineSig: 159 | instruction.Operand = module.ResolveSignature (il.ReadInt32 ()); 160 | break; 161 | case OperandType.InlineString: 162 | instruction.Operand = module.ResolveString (il.ReadInt32 ()); 163 | break; 164 | case OperandType.InlineTok: 165 | case OperandType.InlineType: 166 | case OperandType.InlineMethod: 167 | case OperandType.InlineField: 168 | instruction.Operand = module.ResolveMember (il.ReadInt32 (), type_arguments, method_arguments); 169 | break; 170 | case OperandType.ShortInlineVar: 171 | instruction.Operand = GetVariable (instruction, il.ReadByte ()); 172 | break; 173 | case OperandType.InlineVar: 174 | instruction.Operand = GetVariable (instruction, il.ReadInt16 ()); 175 | break; 176 | default: 177 | throw new NotSupportedException (); 178 | } 179 | } 180 | 181 | void ResolveBranches () 182 | { 183 | foreach (var instruction in instructions) { 184 | switch (instruction.OpCode.OperandType) { 185 | case OperandType.ShortInlineBrTarget: 186 | case OperandType.InlineBrTarget: 187 | instruction.Operand = GetInstruction (instructions, (int) instruction.Operand); 188 | break; 189 | case OperandType.InlineSwitch: 190 | var offsets = (int []) instruction.Operand; 191 | var branches = new Instruction [offsets.Length]; 192 | for (int j = 0; j < offsets.Length; j++) 193 | branches [j] = GetInstruction (instructions, offsets [j]); 194 | 195 | instruction.Operand = branches; 196 | break; 197 | } 198 | } 199 | } 200 | 201 | static Instruction GetInstruction (List instructions, int offset) 202 | { 203 | var size = instructions.Count; 204 | if (offset < 0 || offset > instructions [size - 1].Offset) 205 | return null; 206 | 207 | int min = 0; 208 | int max = size - 1; 209 | while (min <= max) { 210 | int mid = min + ((max - min) / 2); 211 | var instruction = instructions [mid]; 212 | var instruction_offset = instruction.Offset; 213 | 214 | if (offset == instruction_offset) 215 | return instruction; 216 | 217 | if (offset < instruction_offset) 218 | max = mid - 1; 219 | else 220 | min = mid + 1; 221 | } 222 | 223 | return null; 224 | } 225 | 226 | object GetVariable (Instruction instruction, int index) 227 | { 228 | return TargetsLocalVariable (instruction.OpCode) 229 | ? (object) GetLocalVariable (index) 230 | : (object) GetParameter (index); 231 | } 232 | 233 | static bool TargetsLocalVariable (OpCode opcode) 234 | { 235 | return opcode.Name.Contains ("loc"); 236 | } 237 | 238 | LocalVariableInfo GetLocalVariable (int index) 239 | { 240 | return locals [index]; 241 | } 242 | 243 | ParameterInfo GetParameter (int index) 244 | { 245 | if (method.IsStatic) 246 | return parameters [index]; 247 | 248 | if (index == 0) 249 | return this_parameter; 250 | 251 | return parameters [index - 1]; 252 | } 253 | 254 | OpCode ReadOpCode () 255 | { 256 | byte op = il.ReadByte (); 257 | return op != 0xfe 258 | ? one_byte_opcodes [op] 259 | : two_bytes_opcodes [il.ReadByte ()]; 260 | } 261 | 262 | public static List GetInstructions (MethodBase method) 263 | { 264 | var reader = new MethodBodyReader (method); 265 | reader.ReadInstructions (); 266 | return reader.instructions; 267 | } 268 | 269 | class ThisParameter : ParameterInfo 270 | { 271 | public ThisParameter (MethodBase method) 272 | { 273 | this.MemberImpl = method; 274 | this.ClassImpl = method.DeclaringType; 275 | this.NameImpl = "this"; 276 | this.PositionImpl = -1; 277 | } 278 | } 279 | } 280 | } 281 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | ## Mono.Reflection 2 | 3 | Mono.Reflection is an helper library to complement the System.Reflection and System.Reflection.Emit namespaces. 4 | 5 | It works on both Mono >= 2.8 and .net >= 4.0. 6 | 7 | ## API 8 | 9 | *** 10 | 11 | ```csharp 12 | public sealed class Image { 13 | public static bool IsAssembly (string fileName) {} 14 | public static bool IsAssembly (Stream stream) {} 15 | } 16 | ``` 17 | 18 | > Test whether a file is a managed assembly or not. 19 | 20 | *** 21 | 22 | ```csharp 23 | public static class BackingFieldResolver { 24 | public static FieldInfo GetBackingField (this PropertyInfo self) {} 25 | } 26 | ``` 27 | 28 | > Returns the field backing a property or throws an InvalidOperationException. 29 | 30 | *** 31 | 32 | ```csharp 33 | public static class Disassembler { 34 | public static IList GetInstructions (this MethodBase self) {} 35 | } 36 | ``` 37 | 38 | > Returns a read only collection of Instruction representing the 39 | > IL method body or throws an ArgumentException if the method doesn't provide a body. 40 | 41 | *** 42 | 43 | ```csharp 44 | public class Instruction { 45 | public int Offset { get; } 46 | public OpCode OpCode { get; } 47 | public object Operand { get; } 48 | 49 | public Instruction Next { get; } 50 | public Instruction Previous { get; } 51 | } 52 | ``` 53 | 54 | > Represents an IL instruction. 55 | -------------------------------------------------------------------------------- /Test/.gitignore: -------------------------------------------------------------------------------- 1 | bin 2 | obj 3 | *.suo 4 | *.user 5 | -------------------------------------------------------------------------------- /Test/Mono.Reflection.Tests.csproj: -------------------------------------------------------------------------------- 1 |  2 | 3 | netcoreapp2.1;net40 4 | true 5 | 6 | 7 | 8 | 3.11.0 9 | 10 | 11 | 15.9.0 12 | 13 | 14 | 3.12.0 15 | 16 | 17 | 18 | 19 | Mono.Reflection 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | 30 | target.dll 31 | 32 | 33 | 34 | -------------------------------------------------------------------------------- /Test/Mono.Reflection/AssemblyInfo.cs: -------------------------------------------------------------------------------- 1 | using System.Reflection; 2 | using System.Runtime.CompilerServices; 3 | using System.Runtime.InteropServices; 4 | 5 | [assembly: AssemblyTitle ("Mono.Reflection.Tests")] 6 | [assembly: AssemblyDescription ("")] 7 | [assembly: AssemblyConfiguration ("")] 8 | [assembly: AssemblyCompany ("Novell, Inc.")] 9 | [assembly: AssemblyProduct ("Mono.Reflection.Tests")] 10 | [assembly: AssemblyCopyright ("Copyright © Novell, Inc. 2009 - 2010")] 11 | [assembly: AssemblyTrademark ("")] 12 | [assembly: AssemblyCulture ("")] 13 | 14 | [assembly: ComVisible (false)] 15 | 16 | [assembly: Guid ("5f470471-07a4-4f0a-b33c-986b559528f6")] 17 | 18 | [assembly: AssemblyVersion ("2.0.0.0")] 19 | [assembly: AssemblyFileVersion ("2.0.0.0")] 20 | -------------------------------------------------------------------------------- /Test/Mono.Reflection/BackingFieldResolverTest.cs: -------------------------------------------------------------------------------- 1 | // 2 | // DisassemblerTest.cs 3 | // 4 | // Author: 5 | // Jb Evain (jbevain@novell.com) 6 | // 7 | // (C) 2009 - 2010 Novell, Inc. (http://www.novell.com) 8 | // 9 | // Permission is hereby granted, free of charge, to any person obtaining 10 | // a copy of this software and associated documentation files (the 11 | // "Software"), to deal in the Software without restriction, including 12 | // without limitation the rights to use, copy, modify, merge, publish, 13 | // distribute, sublicense, and/or sell copies of the Software, and to 14 | // permit persons to whom the Software is furnished to do so, subject to 15 | // the following conditions: 16 | // 17 | // The above copyright notice and this permission notice shall be 18 | // included in all copies or substantial portions of the Software. 19 | // 20 | // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, 21 | // EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF 22 | // MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND 23 | // NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE 24 | // LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION 25 | // OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION 26 | // WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. 27 | // 28 | 29 | using System; 30 | using System.IO; 31 | using System.Reflection; 32 | using System.Reflection.Emit; 33 | 34 | using NUnit.Framework; 35 | 36 | namespace Mono.Reflection { 37 | 38 | [TestFixture] 39 | public class BackingFieldResolverTest : BaseReflectionTest { 40 | 41 | [Test] 42 | public void StaticOptimizedProperty () 43 | { 44 | AssertBackingField ("sopan", "SOPan"); 45 | } 46 | 47 | [Test] 48 | public void StaticUnoptimizedProperty () 49 | { 50 | AssertBackingField ("supan", "SUPan"); 51 | } 52 | 53 | [Test] 54 | public void InstanceOptimizedProperty () 55 | { 56 | AssertBackingField ("opan", "OPan"); 57 | } 58 | 59 | [Test] 60 | public void InstanceUnoptimizedProperty () 61 | { 62 | AssertBackingField ("upan", "UPan"); 63 | } 64 | 65 | static void AssertBackingField (string field_name, string property_name) 66 | { 67 | var field = GetField (field_name); 68 | var property = GetProperty (property_name); 69 | 70 | Assert.AreEqual (field, property.GetBackingField ()); 71 | } 72 | } 73 | } 74 | -------------------------------------------------------------------------------- /Test/Mono.Reflection/BaseReflectionTest.cs: -------------------------------------------------------------------------------- 1 | // 2 | // DisassemblerTest.cs 3 | // 4 | // Author: 5 | // Jb Evain (jbevain@novell.com) 6 | // 7 | // (C) 2009 - 2010 Novell, Inc. (http://www.novell.com) 8 | // 9 | // Permission is hereby granted, free of charge, to any person obtaining 10 | // a copy of this software and associated documentation files (the 11 | // "Software"), to deal in the Software without restriction, including 12 | // without limitation the rights to use, copy, modify, merge, publish, 13 | // distribute, sublicense, and/or sell copies of the Software, and to 14 | // permit persons to whom the Software is furnished to do so, subject to 15 | // the following conditions: 16 | // 17 | // The above copyright notice and this permission notice shall be 18 | // included in all copies or substantial portions of the Software. 19 | // 20 | // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, 21 | // EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF 22 | // MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND 23 | // NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE 24 | // LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION 25 | // OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION 26 | // WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. 27 | // 28 | 29 | using System; 30 | using System.IO; 31 | using System.Reflection; 32 | using System.Reflection.Emit; 33 | 34 | using NUnit.Framework; 35 | 36 | namespace Mono.Reflection { 37 | 38 | public abstract class BaseReflectionTest { 39 | 40 | protected static MethodBase GetMethod (string name) 41 | { 42 | return test_target.GetType ("Test").GetMember (name, 43 | BindingFlags.Public | BindingFlags.NonPublic | BindingFlags.Static | BindingFlags.Instance) [0] as MethodBase; 44 | } 45 | 46 | protected static PropertyInfo GetProperty (string name) 47 | { 48 | return test_target.GetType ("Test").GetProperty (name, 49 | BindingFlags.Public | BindingFlags.NonPublic | BindingFlags.Static | BindingFlags.Instance); 50 | } 51 | 52 | protected static FieldInfo GetField (string name) 53 | { 54 | return test_target.GetType ("Test").GetField (name, 55 | BindingFlags.Public | BindingFlags.NonPublic | BindingFlags.Static | BindingFlags.Instance); 56 | } 57 | 58 | static Assembly test_target = LoadTestTarget (); 59 | 60 | static Assembly LoadTestTarget () 61 | { 62 | var stream = Assembly.GetExecutingAssembly ().GetManifestResourceStream ("target.dll"); 63 | return Assembly.Load (ToArray (stream)); 64 | } 65 | 66 | static byte [] ToArray (Stream stream) 67 | { 68 | var buffer = new byte [16 * 1024]; 69 | using (MemoryStream ms = new MemoryStream ()) { 70 | int read; 71 | while ((read = stream.Read (buffer, 0, buffer.Length)) > 0) 72 | ms.Write (buffer, 0, read); 73 | 74 | return ms.ToArray (); 75 | } 76 | } 77 | } 78 | } 79 | -------------------------------------------------------------------------------- /Test/Mono.Reflection/DisassemblerTest.cs: -------------------------------------------------------------------------------- 1 | // 2 | // DisassemblerTest.cs 3 | // 4 | // Author: 5 | // Jb Evain (jbevain@novell.com) 6 | // 7 | // (C) 2009 - 2010 Novell, Inc. (http://www.novell.com) 8 | // 9 | // Permission is hereby granted, free of charge, to any person obtaining 10 | // a copy of this software and associated documentation files (the 11 | // "Software"), to deal in the Software without restriction, including 12 | // without limitation the rights to use, copy, modify, merge, publish, 13 | // distribute, sublicense, and/or sell copies of the Software, and to 14 | // permit persons to whom the Software is furnished to do so, subject to 15 | // the following conditions: 16 | // 17 | // The above copyright notice and this permission notice shall be 18 | // included in all copies or substantial portions of the Software. 19 | // 20 | // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, 21 | // EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF 22 | // MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND 23 | // NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE 24 | // LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION 25 | // OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION 26 | // WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. 27 | // 28 | 29 | using System; 30 | using System.IO; 31 | using System.Reflection; 32 | using System.Reflection.Emit; 33 | 34 | using NUnit.Framework; 35 | 36 | namespace Mono.Reflection { 37 | 38 | [TestFixture] 39 | public class DisassemblerTest : BaseReflectionTest { 40 | 41 | [Test] 42 | public void DefaultConstructor () 43 | { 44 | AssertMethod (@" 45 | IL_0000: ldarg.0 46 | IL_0001: call void System.Object::.ctor() 47 | IL_0006: ret 48 | ", ".ctor"); 49 | } 50 | 51 | [Test] 52 | public void ReadField () 53 | { 54 | AssertMethod (@" 55 | IL_0000: ldarg.0 56 | IL_0001: ldfld string Test::str 57 | IL_0006: ret 58 | ", "ReadField"); 59 | } 60 | 61 | [Test] 62 | public void WriteField () 63 | { 64 | AssertMethod (@" 65 | IL_0000: ldarg.0 66 | IL_0001: ldarg val 67 | IL_0005: stfld string Test::str 68 | IL_000a: ret 69 | ", "WriteField"); 70 | } 71 | 72 | [Test] 73 | public void TypeOfString () 74 | { 75 | AssertMethod (@" 76 | IL_0000: ldtoken string 77 | IL_0005: call System.Type System.Type::GetTypeFromHandle(System.RuntimeTypeHandle) 78 | IL_000a: ret 79 | ", "TypeOfString"); 80 | } 81 | 82 | [Test] 83 | public void ShortBranch () 84 | { 85 | AssertMethod (@" 86 | IL_0000: ldarg.1 87 | IL_0001: ldc.i4.0 88 | IL_0002: ble.s IL_0006 89 | IL_0004: ldarg.1 90 | IL_0005: ret 91 | IL_0006: ldc.i4.m1 92 | IL_0007: ret 93 | ", "ShortBranch"); 94 | } 95 | 96 | [Test] 97 | public void Branch () 98 | { 99 | AssertMethod (@" 100 | IL_0000: ldarg.1 101 | IL_0001: ldc.i4.0 102 | IL_0002: ble IL_0009 103 | IL_0007: ldarg.1 104 | IL_0008: ret 105 | IL_0009: ldc.i4.m1 106 | IL_000a: ret 107 | ", "Branch"); 108 | } 109 | 110 | [Test] 111 | public void Switch () 112 | { 113 | AssertMethod (@" 114 | IL_0000: ldarg.1 115 | IL_0001: switch (IL_0018, IL_001a, IL_001c, IL_001e) 116 | IL_0016: br.s IL_001e 117 | IL_0018: ldc.i4.0 118 | IL_0019: ret 119 | IL_001a: ldc.i4.1 120 | IL_001b: ret 121 | IL_001c: ldc.i4.2 122 | IL_001d: ret 123 | IL_001e: ldc.i4.m1 124 | IL_001f: ret 125 | ", "Switch"); 126 | } 127 | 128 | [Test] 129 | public void ThisParameter () 130 | { 131 | AssertMethod (@" 132 | IL_0000: ldarg this 133 | IL_0004: ret 134 | ", "LoadThis"); 135 | } 136 | 137 | public void Foo(string a, string b) 138 | { 139 | 140 | } 141 | 142 | static void AssertMethod (string code, string method_name) 143 | { 144 | var method = GetMethod (method_name); 145 | Assert.AreEqual (Normalize (code), Normalize (Formatter.FormatMethodBody (method))); 146 | } 147 | 148 | static string Normalize (string str) 149 | { 150 | return str.Trim ().Replace ("\r\n", "\n"); 151 | } 152 | } 153 | } 154 | -------------------------------------------------------------------------------- /Test/Mono.Reflection/Formatter.cs: -------------------------------------------------------------------------------- 1 | // 2 | // Formatter.cs 3 | // 4 | // Author: 5 | // Jb Evain (jbevain@novell.com) 6 | // 7 | // (C) 2009 - 2010 Novell, Inc. (http://www.novell.com) 8 | // 9 | // Permission is hereby granted, free of charge, to any person obtaining 10 | // a copy of this software and associated documentation files (the 11 | // "Software"), to deal in the Software without restriction, including 12 | // without limitation the rights to use, copy, modify, merge, publish, 13 | // distribute, sublicense, and/or sell copies of the Software, and to 14 | // permit persons to whom the Software is furnished to do so, subject to 15 | // the following conditions: 16 | // 17 | // The above copyright notice and this permission notice shall be 18 | // included in all copies or substantial portions of the Software. 19 | // 20 | // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, 21 | // EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF 22 | // MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND 23 | // NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE 24 | // LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION 25 | // OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION 26 | // WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. 27 | // 28 | 29 | using System; 30 | using System.IO; 31 | using System.Reflection; 32 | using System.Reflection.Emit; 33 | using System.Text; 34 | 35 | namespace Mono.Reflection { 36 | 37 | public static class Formatter { 38 | 39 | public static string FormatInstruction (Instruction instruction) 40 | { 41 | var writer = new StringWriter (); 42 | WriteInstruction (writer, instruction); 43 | return writer.ToString (); 44 | } 45 | 46 | public static string FormatMethodBody (MethodBase method) 47 | { 48 | var writer = new StringWriter (); 49 | WriteMethodBody (writer, method); 50 | return writer.ToString (); 51 | } 52 | 53 | public static void WriteMethodBody (TextWriter writer, MethodBase method) 54 | { 55 | foreach (var instruction in method.GetInstructions ()) { 56 | writer.Write ('\t'); 57 | WriteInstruction (writer, instruction); 58 | writer.WriteLine (); 59 | } 60 | } 61 | 62 | public static void WriteInstruction (TextWriter writer, Instruction instruction) 63 | { 64 | writer.Write (FormatLabel (instruction.Offset)); 65 | writer.Write (": "); 66 | writer.Write (instruction.OpCode.Name); 67 | WriteOperand (writer, instruction); 68 | } 69 | 70 | static string FormatLabel (int offset) 71 | { 72 | string label = "000" + offset.ToString ("x"); 73 | return "IL_" + label.Substring (label.Length - 4); 74 | } 75 | 76 | static string FormatLabel (Instruction instruction) 77 | { 78 | return FormatLabel (instruction.Offset); 79 | } 80 | 81 | static bool TargetsLocalVariable (OpCode opcode) 82 | { 83 | return opcode.Name.Contains ("loc"); 84 | } 85 | 86 | static void WriteOperand (TextWriter writer, Instruction instruction) 87 | { 88 | var opcode = instruction.OpCode; 89 | var operand = instruction.Operand; 90 | 91 | if (opcode.OperandType == OperandType.InlineNone) 92 | return; 93 | 94 | writer.Write (' '); 95 | 96 | switch (opcode.OperandType) { 97 | case OperandType.ShortInlineBrTarget: 98 | case OperandType.InlineBrTarget: 99 | writer.Write (FormatLabel ((Instruction) operand)); 100 | return; 101 | case OperandType.InlineSwitch: 102 | WriteLabelList (writer, (Instruction []) operand); 103 | return; 104 | case OperandType.InlineString: 105 | writer.Write ("\"" + operand.ToString () + "\""); 106 | return; 107 | case OperandType.ShortInlineVar: 108 | case OperandType.InlineVar: 109 | if (TargetsLocalVariable (opcode)) { 110 | var local = (LocalVariableInfo) operand; 111 | writer.Write ("V_{0}", local.LocalIndex); 112 | return; 113 | } 114 | 115 | var parameter = (ParameterInfo) operand; 116 | writer.Write (parameter.Name); 117 | return; 118 | case OperandType.InlineTok: 119 | case OperandType.InlineType: 120 | case OperandType.InlineMethod: 121 | case OperandType.InlineField: 122 | var member = (MemberInfo) operand; 123 | switch (member.MemberType) { 124 | case MemberTypes.Constructor: 125 | case MemberTypes.Method: 126 | WriteMethodReference (writer, (MethodBase) member); 127 | return; 128 | case MemberTypes.Field: 129 | WriteFieldReference (writer, (FieldInfo) member); 130 | return; 131 | case MemberTypes.TypeInfo: 132 | case MemberTypes.NestedType: 133 | writer.Write (FormatTypeReference ((Type) member)); 134 | return; 135 | default: 136 | throw new NotSupportedException (); 137 | } 138 | case OperandType.InlineI: 139 | case OperandType.ShortInlineI: 140 | case OperandType.InlineR: 141 | case OperandType.ShortInlineR: 142 | case OperandType.InlineI8: 143 | writer.Write (ToInvariantCultureString (operand)); 144 | return; 145 | default: 146 | throw new NotSupportedException (); 147 | } 148 | } 149 | 150 | static void WriteLabelList (TextWriter writer, Instruction [] targets) 151 | { 152 | writer.Write ("("); 153 | 154 | for (int i = 0; i < targets.Length; i++) { 155 | if (i != 0) writer.Write (", "); 156 | writer.Write (FormatLabel (targets [i])); 157 | } 158 | 159 | writer.Write (")"); 160 | } 161 | 162 | static string ToInvariantCultureString (object value) 163 | { 164 | IConvertible convertible = value as IConvertible; 165 | return (null != convertible) 166 | ? convertible.ToString (System.Globalization.CultureInfo.InvariantCulture) 167 | : value.ToString (); 168 | } 169 | 170 | static void WriteFieldReference (TextWriter writer, FieldInfo field) 171 | { 172 | writer.Write (FormatTypeReference (field.FieldType)); 173 | writer.Write (' '); 174 | writer.Write (field.DeclaringType.FullName); 175 | writer.Write ("::"); 176 | writer.Write (field.Name); 177 | } 178 | 179 | static void WriteMethodReference (TextWriter writer, MethodBase method) 180 | { 181 | writer.Write (method is ConstructorInfo ? 182 | FormatTypeReference (typeof (void)) : 183 | FormatTypeReference (((MethodInfo) method).ReturnType)); 184 | 185 | writer.Write (' '); 186 | writer.Write (method.DeclaringType.FullName); 187 | writer.Write ("::"); 188 | writer.Write (method.Name); 189 | writer.Write ("("); 190 | var parameters = method.GetParameters (); 191 | for (int i = 0; i < parameters.Length; ++i) { 192 | if (i > 0) 193 | writer.Write (", "); 194 | 195 | writer.Write (FormatTypeReference (parameters [i].ParameterType)); 196 | } 197 | writer.Write (")"); 198 | } 199 | 200 | static string FormatTypeReference (Type type) 201 | { 202 | string name = type.FullName; 203 | switch (name) { 204 | case "System.Void": return "void"; 205 | case "System.String": return "string"; 206 | case "System.Int16": return "int16"; 207 | case "System.Int32": return "int32"; 208 | case "System.Long": return "int64"; 209 | case "System.Boolean": return "bool"; 210 | case "System.Single": return "float32"; 211 | case "System.Double": return "float64"; 212 | default: return name; 213 | } 214 | } 215 | } 216 | } 217 | -------------------------------------------------------------------------------- /Test/Mono.Reflection/ImageTest.cs: -------------------------------------------------------------------------------- 1 | // 2 | // ImageTest.cs 3 | // 4 | // Author: 5 | // Jb Evain (jbevain@novell.com) 6 | // 7 | // (C) 2009 - 2010 Novell, Inc. (http://www.novell.com) 8 | // 9 | // Permission is hereby granted, free of charge, to any person obtaining 10 | // a copy of this software and associated documentation files (the 11 | // "Software"), to deal in the Software without restriction, including 12 | // without limitation the rights to use, copy, modify, merge, publish, 13 | // distribute, sublicense, and/or sell copies of the Software, and to 14 | // permit persons to whom the Software is furnished to do so, subject to 15 | // the following conditions: 16 | // 17 | // The above copyright notice and this permission notice shall be 18 | // included in all copies or substantial portions of the Software. 19 | // 20 | // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, 21 | // EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF 22 | // MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND 23 | // NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE 24 | // LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION 25 | // OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION 26 | // WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. 27 | // 28 | 29 | using System; 30 | using System.IO; 31 | 32 | using NUnit.Framework; 33 | 34 | namespace Mono.Reflection { 35 | 36 | [TestFixture] 37 | public class ImageTest : BaseReflectionTest { 38 | 39 | [Test] 40 | public void Assembly () 41 | { 42 | Assert.IsTrue (Image.IsAssembly (typeof (Image).Assembly.Location)); 43 | } 44 | 45 | [Test] 46 | public void NotAssembly () 47 | { 48 | Assert.IsFalse (Image.IsAssembly (Path.ChangeExtension (typeof (Image).Assembly.Location, ".pdb"))); 49 | } 50 | } 51 | } 52 | -------------------------------------------------------------------------------- /Test/libs/nunit-2.6.2/license.txt: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jbevain/mono.reflection/6f2c84705f0bf05baef3d7977a8c4b69843ed402/Test/libs/nunit-2.6.2/license.txt -------------------------------------------------------------------------------- /Test/libs/nunit-2.6.2/nunit.core.dll: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jbevain/mono.reflection/6f2c84705f0bf05baef3d7977a8c4b69843ed402/Test/libs/nunit-2.6.2/nunit.core.dll -------------------------------------------------------------------------------- /Test/libs/nunit-2.6.2/nunit.core.interfaces.dll: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jbevain/mono.reflection/6f2c84705f0bf05baef3d7977a8c4b69843ed402/Test/libs/nunit-2.6.2/nunit.core.interfaces.dll -------------------------------------------------------------------------------- /Test/libs/nunit-2.6.2/nunit.framework.dll: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jbevain/mono.reflection/6f2c84705f0bf05baef3d7977a8c4b69843ed402/Test/libs/nunit-2.6.2/nunit.framework.dll -------------------------------------------------------------------------------- /Test/target.dll: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jbevain/mono.reflection/6f2c84705f0bf05baef3d7977a8c4b69843ed402/Test/target.dll -------------------------------------------------------------------------------- /Test/target.il: -------------------------------------------------------------------------------- 1 | .assembly extern mscorlib 2 | { 3 | .publickeytoken = (B7 7A 5C 56 19 34 E0 89) 4 | .ver 2:0:0:0 5 | } 6 | 7 | .assembly target {} 8 | 9 | .module target.dll 10 | 11 | .class private Test extends [mscorlib]System.Object { 12 | 13 | .method public specialname rtspecialname instance void .ctor () cil managed 14 | { 15 | ldarg.0 16 | call instance void [mscorlib]System.Object::.ctor () 17 | ret 18 | } 19 | 20 | .field private string str 21 | 22 | .method public instance string ReadField () cil managed 23 | { 24 | ldarg.0 25 | ldfld string Test::str 26 | ret 27 | } 28 | 29 | .method public instance void WriteField (string val) cil managed 30 | { 31 | ldarg.0 32 | ldarg val 33 | stfld string Test::str 34 | ret 35 | } 36 | 37 | .method public instance class [mscorlib]System.Type TypeOfString () cil managed 38 | { 39 | ldtoken [mscorlib]System.String 40 | call class [mscorlib]System.Type [mscorlib]System.Type::GetTypeFromHandle (valuetype [mscorlib]System.RuntimeTypeHandle) 41 | ret 42 | } 43 | 44 | .method public instance int32 ShortBranch (int32 i) cil managed 45 | { 46 | ldarg.1 47 | ldc.i4.0 48 | ble.s negative 49 | 50 | ldarg.1 51 | ret 52 | 53 | negative: 54 | ldc.i4.m1 55 | ret 56 | } 57 | 58 | .method public instance int32 Branch (int32 i) cil managed 59 | { 60 | ldarg.1 61 | ldc.i4.0 62 | ble negative 63 | 64 | ldarg.1 65 | ret 66 | 67 | negative: 68 | ldc.i4.m1 69 | ret 70 | } 71 | 72 | .method public instance int32 Switch (int32 i) cil managed 73 | { 74 | ldarg.1 75 | switch (zero, one, two, other) 76 | br.s other 77 | 78 | zero: 79 | ldc.i4.0 80 | ret 81 | 82 | one: 83 | ldc.i4.1 84 | ret 85 | 86 | two: 87 | ldc.i4.2 88 | ret 89 | 90 | other: 91 | ldc.i4.m1 92 | ret 93 | } 94 | 95 | .method public instance object LoadThis () cil managed 96 | { 97 | ldarg 0 98 | ret 99 | } 100 | 101 | // optimized instance property 102 | 103 | .field private bool opan 104 | 105 | .property instance bool OPan () { 106 | .get instance bool Test::get_OPan () 107 | .set instance void Test::set_OPan (bool) 108 | } 109 | 110 | .method public hidebysig specialname instance bool get_OPan () cil managed 111 | { 112 | ldarg.0 113 | ldfld bool Test::opan 114 | ret 115 | } 116 | 117 | .method public hidebysig specialname instance void set_OPan (bool val) cil managed 118 | { 119 | ldarg.0 120 | ldarg.1 121 | stfld bool Test::opan 122 | ret 123 | } 124 | 125 | // optimized static property 126 | 127 | .field private static bool sopan 128 | 129 | .property bool SOPan () { 130 | .get bool Test::get_SOPan () 131 | .set void Test::set_SOPan (bool) 132 | } 133 | 134 | .method public hidebysig specialname static bool get_SOPan () cil managed 135 | { 136 | ldsfld bool Test::sopan 137 | ret 138 | } 139 | 140 | .method public hidebysig specialname static void set_SOPan (bool val) cil managed 141 | { 142 | ldarg.0 143 | stsfld bool Test::sopan 144 | ret 145 | } 146 | 147 | // unoptimized instance property 148 | 149 | .field private bool upan 150 | 151 | .property instance bool UPan () { 152 | .get instance bool Test::get_UPan () 153 | .set instance void Test::set_UPan (bool) 154 | } 155 | 156 | .method public hidebysig specialname instance bool get_UPan () cil managed 157 | { 158 | .locals init (bool b) 159 | nop 160 | ldarg.0 161 | ldfld bool Test::upan 162 | stloc.0 163 | br.s retval 164 | retval: 165 | ldloc.0 166 | ret 167 | } 168 | 169 | .method public hidebysig specialname instance void set_UPan (bool val) cil managed 170 | { 171 | nop 172 | ldarg.0 173 | ldarg.1 174 | stfld bool Test::upan 175 | ret 176 | } 177 | 178 | // unoptimized static property 179 | 180 | .field private static bool supan 181 | 182 | .property bool SUPan () { 183 | .get bool Test::get_SUPan () 184 | .set void Test::set_SUPan (bool) 185 | } 186 | 187 | .method public hidebysig specialname static bool get_SUPan () cil managed 188 | { 189 | .locals init (bool val) 190 | nop 191 | ldsfld bool Test::supan 192 | stloc.0 193 | br.s retval 194 | retval: 195 | ldloc.0 196 | ret 197 | } 198 | 199 | .method public hidebysig specialname static void set_SUPan (bool val) cil managed 200 | { 201 | nop 202 | ldarg.0 203 | stsfld bool Test::supan 204 | ret 205 | } 206 | } 207 | -------------------------------------------------------------------------------- /mono.snk: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jbevain/mono.reflection/6f2c84705f0bf05baef3d7977a8c4b69843ed402/mono.snk --------------------------------------------------------------------------------