/* Copyright (C) 2014-2019 de4dot@gmail.com This file is part of dnSpy dnSpy is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version. dnSpy is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with dnSpy. If not, see . */ using System; using System.Collections.Generic; using System.Collections.ObjectModel; using System.Diagnostics; using System.IO; using System.Linq; using System.Reflection; using System.Runtime.InteropServices; using dnlib.DotNet.MD; using DNE = dnlib.DotNet.Emit; namespace dnSpy.Debugger.DotNet.Metadata.Impl { /// /// /// public static class ReflectionTests { const bool TESTEXCEPTIONS = false; /* CorDebug code: 1. Change compile action from None to Compile in the file properties in VS 2. Load some non-loaded asms in dnSpy's StartupClass.Main. This prevents some ResolveExceptions from being thrown System.Reflection.Assembly.Load(@"System.Security, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a"); System.Reflection.Assembly.Load(@"System.Data.SqlXml, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089"); 3. Add Test(); to the end of DbgEngineImpl.BreakCore() 4. Add the code below to the same class (DbgEngineImpl) 5. Debug dnSpy with VS 6. Debug dnSpy with dnSpy, and when CPU usage is 0%, break the process 7. Check the Output window, eg.: ... (88/101): System.ObjectModel, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a (89/101): System.Reflection.Primitives, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a (90/101): System.Collections.Concurrent, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a ... 8. If it fails, you'll hit a BP in Verify(). COM MD API doesn't have a way of getting the entry point token so it will fail when testing an exe file. sealed class DmdEvaluatorImpl2 : DmdEvaluator { public override object Invoke(IDmdEvaluationContext context, DmdMethodBase method, object obj, object[] parameters) => throw new NotImplementedException(); public override object LoadField(IDmdEvaluationContext context, DmdFieldInfo field, object obj) => throw new NotImplementedException(); public override void StoreField(IDmdEvaluationContext context, DmdFieldInfo field, object obj, object value) => throw new NotImplementedException(); public override void Invoke(IDmdEvaluationContext context, DmdMethodBase method, object obj, object[] parameters, Action callback) => throw new NotImplementedException(); public override void LoadField(IDmdEvaluationContext context, DmdFieldInfo field, object obj, Action callback) => throw new NotImplementedException(); public override void StoreField(IDmdEvaluationContext context, DmdFieldInfo field, object obj, object value, Action callback) => throw new NotImplementedException(); } sealed class ModuleNameProvider { readonly Dictionary toName; public ModuleNameProvider() { toName = new Dictionary(StringComparer.OrdinalIgnoreCase); foreach (ProcessModule module in Process.GetCurrentProcess().Modules) { var name = Path.GetFileName(module.FileName); if (name.EndsWith(".ni.dll", StringComparison.OrdinalIgnoreCase)) toName[name.Substring(0, name.Length - ".ni.dll".Length) + ".dll"] = module.FileName; } } public string GetModuleFilename(DbgModule module) { if (toName.TryGetValue(Path.GetFileName(module.Filename), out var filename)) return filename; return module.Filename; } } sealed class DmdDataStreamImpl : DmdDataStream { readonly DataReader reader; public DmdDataStreamImpl(DataReader reader) => this.reader = reader; public override long Position { get => reader.Position; set => reader.Position = (uint)value; } public override long Length => reader.Length; public override byte ReadByte() => reader.ReadByte(); public override ushort ReadUInt16() => reader.ReadUInt16(); public override uint ReadUInt32() => reader.ReadUInt32(); public override ulong ReadUInt64() => reader.ReadUInt64(); public override float ReadSingle() => reader.ReadSingle(); public override double ReadDouble() => reader.ReadDouble(); public override byte[] ReadBytes(int length) => reader.ReadBytes(length); public override void Dispose() { } } void Test() { var runtime = DmdRuntimeFactory.CreateRuntime(new DmdEvaluatorImpl2(), IntPtr.Size == 4 ? DmdImageFileMachine.I386 : DmdImageFileMachine.AMD64); var dad = TryGetEngineAppDomain(dnDebugger.Processes.First().AppDomains[0]).AppDomain; var ad = runtime.CreateAppDomain(dad.Id); var moduleNameProvider = new ModuleNameProvider(); bool useComMD = true; useComMD = false; var comMdDispatcher = useComMD ? new DmdDispatcherImpl(this) : null; foreach (var dmod in dad.Modules) { if (!dmod.IsDotNetModule()) continue; if (dmod.IsDynamic || dmod.IsInMemory) continue; DmdAssembly asm; if (useComMD) { if (!TryGetModuleData(dmod, out var data)) throw new InvalidOperationException(); var mdi = data.DnModule.CorModule.GetMetaDataInterface(); var dynamicModuleHelper = new DmdDynamicModuleHelperImpl(this); asm = ad.CreateAssembly(mdi, dynamicModuleHelper, comMdDispatcher, dmod.IsInMemory, dmod.IsDynamic, dmod.Filename, dmod.Filename); } else asm = ad.CreateAssembly(moduleNameProvider.GetModuleFilename(dmod), true, dmod.IsInMemory, dmod.IsDynamic, dmod.Filename, dmod.Filename); asm.ManifestModule.GetOrCreateData(() => dmod); } // Run it on the UI thread to test the COM MD code System.Windows.Application.Current.Dispatcher.BeginInvoke(System.Windows.Threading.DispatcherPriority.Background, new Action(() => { ReflectionTests.Test(ad); })); } */ /// /// /// /// public static void Test(DmdAppDomain ad) { { var t2 = typeof(Dictionary<,>); var t1 = ad.GetType(t2); TestTypeSpecs(t1, t2); TestTypeSpecs(t1.MakeGenericType(ad.System_String, ad.GetType(typeof(List>))), t2.MakeGenericType(typeof(string), typeof(List>))); TestTypeSpecs(ad.GetType(typeof(Dictionary<,>)).GetGenericArguments()[0], typeof(Dictionary<,>).GetGenericArguments()[0]); TestTypeSpecs(ad.GetType(typeof(Nullable<>)).GetGenericArguments()[0], typeof(Nullable<>).GetGenericArguments()[0]); } { var t1 = ad.System_Array; var t2 = typeof(Array); var m1 = t1.GetMethod("Resize"); var m2 = t2.GetMethod("Resize"); Test(m1, m2); Test(m1.MakeGenericMethod(ad.System_SByte), m2.MakeGenericMethod(typeof(sbyte))); Verify(ad.System_Int32.IsSubclassOf(ad.System_ValueType) == typeof(int).IsSubclassOf(typeof(ValueType))); Verify(ad.System_ValueType.IsSubclassOf(ad.System_Int32) == typeof(ValueType).IsSubclassOf(typeof(int))); Verify(ad.System_Int32.IsAssignableFrom(ad.System_ValueType) == typeof(int).IsAssignableFrom(typeof(ValueType))); Verify(ad.System_ValueType.IsAssignableFrom(ad.System_Int32) == typeof(ValueType).IsAssignableFrom(typeof(int))); Verify(ad.System_Int32.IsEquivalentTo(ad.System_ValueType) == typeof(int).IsEquivalentTo(typeof(ValueType))); Verify(ad.System_ValueType.IsEquivalentTo(ad.System_Int32) == typeof(ValueType).IsEquivalentTo(typeof(int))); Verify(ad.System_Int32.IsEquivalentTo(ad.System_Int32) == typeof(int).IsEquivalentTo(typeof(int))); t2 = typeof(List); t1 = ad.GetType(t2); { SimpleTest(t1.GetMember("CopyTo"), t2.GetMember("CopyTo")); var names = new[] { "CopyTo", "ToString", ".ctor", ".cctor", "ToArray", "EnsureCapacity", "Synchronized", "IsCompatibleObject", }; foreach (var name in names) { SimpleTest(t1.GetMember(name, DmdBindingFlags.Public | DmdBindingFlags.Instance), t2.GetMember(name, BindingFlags.Public | BindingFlags.Instance)); SimpleTest(t1.GetMember(name, DmdBindingFlags.NonPublic | DmdBindingFlags.Instance), t2.GetMember(name, BindingFlags.NonPublic | BindingFlags.Instance)); SimpleTest(t1.GetMember(name, DmdBindingFlags.Public | DmdBindingFlags.Static), t2.GetMember(name, BindingFlags.Public | BindingFlags.Static)); SimpleTest(t1.GetMember(name, DmdBindingFlags.NonPublic | DmdBindingFlags.Static), t2.GetMember(name, BindingFlags.NonPublic | BindingFlags.Static)); SimpleTest(t1.GetMember(name, DmdMemberTypes.Method, DmdBindingFlags.Public | DmdBindingFlags.Instance), t2.GetMember(name, MemberTypes.Method, BindingFlags.Public | BindingFlags.Instance)); SimpleTest(t1.GetMember(name, DmdMemberTypes.Method, DmdBindingFlags.NonPublic | DmdBindingFlags.Instance), t2.GetMember(name, MemberTypes.Method, BindingFlags.NonPublic | BindingFlags.Instance)); SimpleTest(t1.GetMember(name, DmdMemberTypes.Method, DmdBindingFlags.Public | DmdBindingFlags.Static), t2.GetMember(name, MemberTypes.Method, BindingFlags.Public | BindingFlags.Static)); SimpleTest(t1.GetMember(name, DmdMemberTypes.Method, DmdBindingFlags.NonPublic | DmdBindingFlags.Static), t2.GetMember(name, MemberTypes.Method, BindingFlags.NonPublic | BindingFlags.Static)); SimpleTest(t1.GetMember(name, DmdMemberTypes.Constructor, DmdBindingFlags.Public | DmdBindingFlags.Instance), t2.GetMember(name, MemberTypes.Constructor, BindingFlags.Public | BindingFlags.Instance)); SimpleTest(t1.GetMember(name, DmdMemberTypes.Constructor, DmdBindingFlags.NonPublic | DmdBindingFlags.Instance), t2.GetMember(name, MemberTypes.Constructor, BindingFlags.NonPublic | BindingFlags.Instance)); SimpleTest(t1.GetMember(name, DmdMemberTypes.Constructor, DmdBindingFlags.Public | DmdBindingFlags.Static), t2.GetMember(name, MemberTypes.Constructor, BindingFlags.Public | BindingFlags.Static)); SimpleTest(t1.GetMember(name, DmdMemberTypes.Constructor, DmdBindingFlags.NonPublic | DmdBindingFlags.Static), t2.GetMember(name, MemberTypes.Constructor, BindingFlags.NonPublic | BindingFlags.Static)); SimpleTest(t1.GetMember(name, DmdMemberTypes.Method | DmdMemberTypes.Constructor, DmdBindingFlags.Public | DmdBindingFlags.Instance), t2.GetMember(name, MemberTypes.Method | MemberTypes.Constructor, BindingFlags.Public | BindingFlags.Instance)); SimpleTest(t1.GetMember(name, DmdMemberTypes.Method | DmdMemberTypes.Constructor, DmdBindingFlags.NonPublic | DmdBindingFlags.Instance), t2.GetMember(name, MemberTypes.Method | MemberTypes.Constructor, BindingFlags.NonPublic | BindingFlags.Instance)); SimpleTest(t1.GetMember(name, DmdMemberTypes.Method | DmdMemberTypes.Constructor, DmdBindingFlags.Public | DmdBindingFlags.Static), t2.GetMember(name, MemberTypes.Method | MemberTypes.Constructor, BindingFlags.Public | BindingFlags.Static)); SimpleTest(t1.GetMember(name, DmdMemberTypes.Method | DmdMemberTypes.Constructor, DmdBindingFlags.NonPublic | DmdBindingFlags.Static), t2.GetMember(name, MemberTypes.Method | MemberTypes.Constructor, BindingFlags.NonPublic | BindingFlags.Static)); SimpleTest(t1.GetMember(name, DmdMemberTypes.Method | DmdMemberTypes.Constructor | DmdMemberTypes.Field, DmdBindingFlags.Public | DmdBindingFlags.Instance), t2.GetMember(name, MemberTypes.Method | MemberTypes.Constructor | MemberTypes.Field, BindingFlags.Public | BindingFlags.Instance)); SimpleTest(t1.GetMember(name, DmdMemberTypes.Method | DmdMemberTypes.Constructor | DmdMemberTypes.Field, DmdBindingFlags.NonPublic | DmdBindingFlags.Instance), t2.GetMember(name, MemberTypes.Method | MemberTypes.Constructor | MemberTypes.Field, BindingFlags.NonPublic | BindingFlags.Instance)); SimpleTest(t1.GetMember(name, DmdMemberTypes.Method | DmdMemberTypes.Constructor | DmdMemberTypes.Field, DmdBindingFlags.Public | DmdBindingFlags.Static), t2.GetMember(name, MemberTypes.Method | MemberTypes.Constructor | MemberTypes.Field, BindingFlags.Public | BindingFlags.Static)); SimpleTest(t1.GetMember(name, DmdMemberTypes.Method | DmdMemberTypes.Constructor | DmdMemberTypes.Field, DmdBindingFlags.NonPublic | DmdBindingFlags.Static), t2.GetMember(name, MemberTypes.Method | MemberTypes.Constructor | MemberTypes.Field, BindingFlags.NonPublic | BindingFlags.Static)); } } { SimpleTest(t1.GetMember("_items"), t2.GetMember("_items")); var names = new[] { "_defaultCapacity", "_items", "_size", "_emptyArray", }; foreach (var name in names) { SimpleTest(t1.GetMember(name, DmdBindingFlags.Public | DmdBindingFlags.Instance), t2.GetMember(name, BindingFlags.Public | BindingFlags.Instance)); SimpleTest(t1.GetMember(name, DmdBindingFlags.NonPublic | DmdBindingFlags.Instance), t2.GetMember(name, BindingFlags.NonPublic | BindingFlags.Instance)); SimpleTest(t1.GetMember(name, DmdBindingFlags.Public | DmdBindingFlags.Static), t2.GetMember(name, BindingFlags.Public | BindingFlags.Static)); SimpleTest(t1.GetMember(name, DmdBindingFlags.NonPublic | DmdBindingFlags.Static), t2.GetMember(name, BindingFlags.NonPublic | BindingFlags.Static)); SimpleTest(t1.GetMember(name, DmdMemberTypes.Field, DmdBindingFlags.Public | DmdBindingFlags.Instance), t2.GetMember(name, MemberTypes.Field, BindingFlags.Public | BindingFlags.Instance)); SimpleTest(t1.GetMember(name, DmdMemberTypes.Field, DmdBindingFlags.NonPublic | DmdBindingFlags.Instance), t2.GetMember(name, MemberTypes.Field, BindingFlags.NonPublic | BindingFlags.Instance)); SimpleTest(t1.GetMember(name, DmdMemberTypes.Field, DmdBindingFlags.Public | DmdBindingFlags.Static), t2.GetMember(name, MemberTypes.Field, BindingFlags.Public | BindingFlags.Static)); SimpleTest(t1.GetMember(name, DmdMemberTypes.Field, DmdBindingFlags.NonPublic | DmdBindingFlags.Static), t2.GetMember(name, MemberTypes.Field, BindingFlags.NonPublic | BindingFlags.Static)); SimpleTest(t1.GetMember(name, DmdMemberTypes.Field | DmdMemberTypes.Constructor, DmdBindingFlags.Public | DmdBindingFlags.Instance), t2.GetMember(name, MemberTypes.Field | MemberTypes.Constructor, BindingFlags.Public | BindingFlags.Instance)); SimpleTest(t1.GetMember(name, DmdMemberTypes.Field | DmdMemberTypes.Constructor, DmdBindingFlags.NonPublic | DmdBindingFlags.Instance), t2.GetMember(name, MemberTypes.Field | MemberTypes.Constructor, BindingFlags.NonPublic | BindingFlags.Instance)); SimpleTest(t1.GetMember(name, DmdMemberTypes.Field | DmdMemberTypes.Constructor, DmdBindingFlags.Public | DmdBindingFlags.Static), t2.GetMember(name, MemberTypes.Field | MemberTypes.Constructor, BindingFlags.Public | BindingFlags.Static)); SimpleTest(t1.GetMember(name, DmdMemberTypes.Field | DmdMemberTypes.Constructor, DmdBindingFlags.NonPublic | DmdBindingFlags.Static), t2.GetMember(name, MemberTypes.Field | MemberTypes.Constructor, BindingFlags.NonPublic | BindingFlags.Static)); } } { SimpleTest(t1.GetMember("Count"), t2.GetMember("Count")); var names = new[] { "Count", "Capacity", "Item", }; foreach (var name in names) { SimpleTest(t1.GetMember(name, DmdBindingFlags.Public | DmdBindingFlags.Instance), t2.GetMember(name, BindingFlags.Public | BindingFlags.Instance)); SimpleTest(t1.GetMember(name, DmdBindingFlags.NonPublic | DmdBindingFlags.Instance), t2.GetMember(name, BindingFlags.NonPublic | BindingFlags.Instance)); SimpleTest(t1.GetMember(name, DmdBindingFlags.Public | DmdBindingFlags.Static), t2.GetMember(name, BindingFlags.Public | BindingFlags.Static)); SimpleTest(t1.GetMember(name, DmdBindingFlags.NonPublic | DmdBindingFlags.Static), t2.GetMember(name, BindingFlags.NonPublic | BindingFlags.Static)); SimpleTest(t1.GetMember(name, DmdMemberTypes.Property, DmdBindingFlags.Public | DmdBindingFlags.Instance), t2.GetMember(name, MemberTypes.Property, BindingFlags.Public | BindingFlags.Instance)); SimpleTest(t1.GetMember(name, DmdMemberTypes.Property, DmdBindingFlags.NonPublic | DmdBindingFlags.Instance), t2.GetMember(name, MemberTypes.Property, BindingFlags.NonPublic | BindingFlags.Instance)); SimpleTest(t1.GetMember(name, DmdMemberTypes.Property, DmdBindingFlags.Public | DmdBindingFlags.Static), t2.GetMember(name, MemberTypes.Property, BindingFlags.Public | BindingFlags.Static)); SimpleTest(t1.GetMember(name, DmdMemberTypes.Property, DmdBindingFlags.NonPublic | DmdBindingFlags.Static), t2.GetMember(name, MemberTypes.Property, BindingFlags.NonPublic | BindingFlags.Static)); SimpleTest(t1.GetMember(name, DmdMemberTypes.Property | DmdMemberTypes.Constructor, DmdBindingFlags.Public | DmdBindingFlags.Instance), t2.GetMember(name, MemberTypes.Property | MemberTypes.Constructor, BindingFlags.Public | BindingFlags.Instance)); SimpleTest(t1.GetMember(name, DmdMemberTypes.Property | DmdMemberTypes.Constructor, DmdBindingFlags.NonPublic | DmdBindingFlags.Instance), t2.GetMember(name, MemberTypes.Property | MemberTypes.Constructor, BindingFlags.NonPublic | BindingFlags.Instance)); SimpleTest(t1.GetMember(name, DmdMemberTypes.Property | DmdMemberTypes.Constructor, DmdBindingFlags.Public | DmdBindingFlags.Static), t2.GetMember(name, MemberTypes.Property | MemberTypes.Constructor, BindingFlags.Public | BindingFlags.Static)); SimpleTest(t1.GetMember(name, DmdMemberTypes.Property | DmdMemberTypes.Constructor, DmdBindingFlags.NonPublic | DmdBindingFlags.Static), t2.GetMember(name, MemberTypes.Property | MemberTypes.Constructor, BindingFlags.NonPublic | BindingFlags.Static)); } } { SimpleTest(t1.GetMember("Enumerator"), t2.GetMember("Enumerator")); var names = new[] { "Enumerator", "SynchronizedList", }; foreach (var name in names) { SimpleTest(t1.GetMember(name, DmdBindingFlags.Public | DmdBindingFlags.Instance), t2.GetMember(name, BindingFlags.Public | BindingFlags.Instance)); SimpleTest(t1.GetMember(name, DmdBindingFlags.NonPublic | DmdBindingFlags.Instance), t2.GetMember(name, BindingFlags.NonPublic | BindingFlags.Instance)); SimpleTest(t1.GetMember(name, DmdBindingFlags.Public | DmdBindingFlags.Static), t2.GetMember(name, BindingFlags.Public | BindingFlags.Static)); SimpleTest(t1.GetMember(name, DmdBindingFlags.NonPublic | DmdBindingFlags.Static), t2.GetMember(name, BindingFlags.NonPublic | BindingFlags.Static)); SimpleTest(t1.GetMember(name, DmdMemberTypes.NestedType, DmdBindingFlags.Public | DmdBindingFlags.Instance), t2.GetMember(name, MemberTypes.NestedType, BindingFlags.Public | BindingFlags.Instance)); SimpleTest(t1.GetMember(name, DmdMemberTypes.NestedType, DmdBindingFlags.NonPublic | DmdBindingFlags.Instance), t2.GetMember(name, MemberTypes.NestedType, BindingFlags.NonPublic | BindingFlags.Instance)); SimpleTest(t1.GetMember(name, DmdMemberTypes.NestedType, DmdBindingFlags.Public | DmdBindingFlags.Static), t2.GetMember(name, MemberTypes.NestedType, BindingFlags.Public | BindingFlags.Static)); SimpleTest(t1.GetMember(name, DmdMemberTypes.NestedType, DmdBindingFlags.NonPublic | DmdBindingFlags.Static), t2.GetMember(name, MemberTypes.NestedType, BindingFlags.NonPublic | BindingFlags.Static)); SimpleTest(t1.GetMember(name, DmdMemberTypes.NestedType | DmdMemberTypes.Constructor, DmdBindingFlags.Public | DmdBindingFlags.Instance), t2.GetMember(name, MemberTypes.NestedType | MemberTypes.Constructor, BindingFlags.Public | BindingFlags.Instance)); SimpleTest(t1.GetMember(name, DmdMemberTypes.NestedType | DmdMemberTypes.Constructor, DmdBindingFlags.NonPublic | DmdBindingFlags.Instance), t2.GetMember(name, MemberTypes.NestedType | MemberTypes.Constructor, BindingFlags.NonPublic | BindingFlags.Instance)); SimpleTest(t1.GetMember(name, DmdMemberTypes.NestedType | DmdMemberTypes.Constructor, DmdBindingFlags.Public | DmdBindingFlags.Static), t2.GetMember(name, MemberTypes.NestedType | MemberTypes.Constructor, BindingFlags.Public | BindingFlags.Static)); SimpleTest(t1.GetMember(name, DmdMemberTypes.NestedType | DmdMemberTypes.Constructor, DmdBindingFlags.NonPublic | DmdBindingFlags.Static), t2.GetMember(name, MemberTypes.NestedType | MemberTypes.Constructor, BindingFlags.NonPublic | BindingFlags.Static)); SimpleTest(t1.GetMember(name, DmdMemberTypes.TypeInfo, DmdBindingFlags.Public | DmdBindingFlags.Instance), t2.GetMember(name, MemberTypes.TypeInfo, BindingFlags.Public | BindingFlags.Instance)); SimpleTest(t1.GetMember(name, DmdMemberTypes.TypeInfo, DmdBindingFlags.NonPublic | DmdBindingFlags.Instance), t2.GetMember(name, MemberTypes.TypeInfo, BindingFlags.NonPublic | BindingFlags.Instance)); SimpleTest(t1.GetMember(name, DmdMemberTypes.TypeInfo, DmdBindingFlags.Public | DmdBindingFlags.Static), t2.GetMember(name, MemberTypes.TypeInfo, BindingFlags.Public | BindingFlags.Static)); SimpleTest(t1.GetMember(name, DmdMemberTypes.TypeInfo, DmdBindingFlags.NonPublic | DmdBindingFlags.Static), t2.GetMember(name, MemberTypes.TypeInfo, BindingFlags.NonPublic | BindingFlags.Static)); SimpleTest(t1.GetMember(name, DmdMemberTypes.TypeInfo | DmdMemberTypes.Constructor, DmdBindingFlags.Public | DmdBindingFlags.Instance), t2.GetMember(name, MemberTypes.TypeInfo | MemberTypes.Constructor, BindingFlags.Public | BindingFlags.Instance)); SimpleTest(t1.GetMember(name, DmdMemberTypes.TypeInfo | DmdMemberTypes.Constructor, DmdBindingFlags.NonPublic | DmdBindingFlags.Instance), t2.GetMember(name, MemberTypes.TypeInfo | MemberTypes.Constructor, BindingFlags.NonPublic | BindingFlags.Instance)); SimpleTest(t1.GetMember(name, DmdMemberTypes.TypeInfo | DmdMemberTypes.Constructor, DmdBindingFlags.Public | DmdBindingFlags.Static), t2.GetMember(name, MemberTypes.TypeInfo | MemberTypes.Constructor, BindingFlags.Public | BindingFlags.Static)); SimpleTest(t1.GetMember(name, DmdMemberTypes.TypeInfo | DmdMemberTypes.Constructor, DmdBindingFlags.NonPublic | DmdBindingFlags.Static), t2.GetMember(name, MemberTypes.TypeInfo | MemberTypes.Constructor, BindingFlags.NonPublic | BindingFlags.Static)); SimpleTest(t1.GetMember(name, DmdMemberTypes.NestedType | DmdMemberTypes.TypeInfo, DmdBindingFlags.Public | DmdBindingFlags.Instance), t2.GetMember(name, MemberTypes.NestedType | MemberTypes.TypeInfo, BindingFlags.Public | BindingFlags.Instance)); SimpleTest(t1.GetMember(name, DmdMemberTypes.NestedType | DmdMemberTypes.TypeInfo, DmdBindingFlags.NonPublic | DmdBindingFlags.Instance), t2.GetMember(name, MemberTypes.NestedType | MemberTypes.TypeInfo, BindingFlags.NonPublic | BindingFlags.Instance)); SimpleTest(t1.GetMember(name, DmdMemberTypes.NestedType | DmdMemberTypes.TypeInfo, DmdBindingFlags.Public | DmdBindingFlags.Static), t2.GetMember(name, MemberTypes.NestedType | MemberTypes.TypeInfo, BindingFlags.Public | BindingFlags.Static)); SimpleTest(t1.GetMember(name, DmdMemberTypes.NestedType | DmdMemberTypes.TypeInfo, DmdBindingFlags.NonPublic | DmdBindingFlags.Static), t2.GetMember(name, MemberTypes.NestedType | MemberTypes.TypeInfo, BindingFlags.NonPublic | BindingFlags.Static)); SimpleTest(t1.GetMember(name, DmdMemberTypes.NestedType | DmdMemberTypes.TypeInfo | DmdMemberTypes.Constructor, DmdBindingFlags.Public | DmdBindingFlags.Instance), t2.GetMember(name, MemberTypes.NestedType | MemberTypes.TypeInfo | MemberTypes.Constructor, BindingFlags.Public | BindingFlags.Instance)); SimpleTest(t1.GetMember(name, DmdMemberTypes.NestedType | DmdMemberTypes.TypeInfo | DmdMemberTypes.Constructor, DmdBindingFlags.NonPublic | DmdBindingFlags.Instance), t2.GetMember(name, MemberTypes.NestedType | MemberTypes.TypeInfo | MemberTypes.Constructor, BindingFlags.NonPublic | BindingFlags.Instance)); SimpleTest(t1.GetMember(name, DmdMemberTypes.NestedType | DmdMemberTypes.TypeInfo | DmdMemberTypes.Constructor, DmdBindingFlags.Public | DmdBindingFlags.Static), t2.GetMember(name, MemberTypes.NestedType | MemberTypes.TypeInfo | MemberTypes.Constructor, BindingFlags.Public | BindingFlags.Static)); SimpleTest(t1.GetMember(name, DmdMemberTypes.NestedType | DmdMemberTypes.TypeInfo | DmdMemberTypes.Constructor, DmdBindingFlags.NonPublic | DmdBindingFlags.Static), t2.GetMember(name, MemberTypes.NestedType | MemberTypes.TypeInfo | MemberTypes.Constructor, BindingFlags.NonPublic | BindingFlags.Static)); } } } foreach (var asm in ad.GetAssemblies()) { if (asm.IsDynamic || asm.IsInMemory) continue; try { Assembly.Load(asm.GetName().ToString()); } catch (System.IO.FileNotFoundException) { Assembly.LoadFrom(asm.Location); } } var dict = new Dictionary(StringComparer.Ordinal); foreach (var asm in AppDomain.CurrentDomain.GetAssemblies()) dict.Add(asm.GetName().ToString(), asm); var allAsms = ad.GetAssemblies(); for (int i = 0; i < allAsms.Length; i++) { var asm = allAsms[i]; Debug.WriteLine($"({i + 1}/{allAsms.Length}): {asm.ToString()}"); switch (asm.GetName().Name) { case "Microsoft.CodeAnalysis.CSharp": case "Microsoft.CodeAnalysis.CSharp.Features": case "Microsoft.CodeAnalysis.VisualBasic": case "Microsoft.CodeAnalysis.VisualBasic.Features": // Reflection returns dupe props so ignore these assemblies. // Seems like it compares the raw property signatures but it should compare the signatures // after replacing generic params with generic args. continue; } Test(asm, dict[asm.GetName().ToString()]); } } static bool Verify(bool result) { if (!result) System.Diagnostics.Debugger.Break(); return result; } const DmdBindingFlags all1a = DmdBindingFlags.Public | DmdBindingFlags.NonPublic | DmdBindingFlags.Instance | DmdBindingFlags.Static; const BindingFlags all2a = BindingFlags.Public | BindingFlags.NonPublic | BindingFlags.Instance | BindingFlags.Static; const DmdBindingFlags all1b = all1a | DmdBindingFlags.FlattenHierarchy; const BindingFlags all2b = all2a | BindingFlags.FlattenHierarchy; static readonly DmdBindingFlags[] bindingFlags1 = new[] { all1a, all1b }; static readonly BindingFlags[] bindingFlags2 = new[] { all2a, all2b }; static void Test(DmdAssembly asm1, Assembly asm2) { Verify(asm1.ToString() == asm2.ToString()); Verify(DmdAssembly.CreateQualifiedName("xyz", "123") == Assembly.CreateQualifiedName("xyz", "123")); Test(asm1.GetName(), asm2.GetName(), asm1.Location.IndexOf("GAC", StringComparison.OrdinalIgnoreCase) < 0); Verify(asm1.FullName == asm2.FullName); //Verify(asm1.Location == asm2.Location); Verify(asm1.ImageRuntimeVersion == asm2.ImageRuntimeVersion); Verify(asm1.EntryPoint?.ToString() == asm2.EntryPoint?.ToString()); Verify(asm1.ManifestModule.ToString() == asm2.ManifestModule.ToString()); Test(FilterOutComObject(asm1.AppDomain, asm1.ExportedTypes.ToArray()), asm2.ExportedTypes.ToArray()); Test(FilterOutComObject(asm1.AppDomain, asm1.GetExportedTypes()), asm2.GetExportedTypes()); try { Test(FilterOutTransparentProxy(asm1.GetTypes().Skip(1).ToArray()), asm2.GetTypes()); } catch (ReflectionTypeLoadException) { Debug.WriteLine($"Couldn't load all types: {asm2}"); return; } Test(FilterOutSecurityAttributes(asm1.AppDomain, asm1.GetCustomAttributesData()), asm2.GetCustomAttributesData()); Test(asm1.GetReferencedAssemblies(), asm2.GetReferencedAssemblies()); TestAssemblyName(); var mod1 = asm1.ManifestModule; var mod2 = asm2.ManifestModule; Test(mod1, mod2); for (int rid = 2; ; rid++) { var t1 = mod1.ResolveType(0x02000000 + rid, DmdResolveOptions.None); Type t2; try { t2 = mod2.ResolveType(0x02000000 + rid); } catch (ArgumentOutOfRangeException) { t2 = null; } catch (ArgumentException) { continue; } Verify((t1 is not null) == (t2 is not null)); if (t1 is null) break; TestTypes(t1, t2); } } static void TestAssemblyName() { var n1 = new DmdAssemblyName(); var n2 = new AssemblyName(); Test(n1, n2); n1 = new DmdAssemblyName("mscorlib, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089"); n2 = new AssemblyName("mscorlib, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089"); Test(n1, n2); n1.ContentType = DmdAssemblyContentType.WindowsRuntime; n2.ContentType = AssemblyContentType.WindowsRuntime; Verify((int)n1.ContentType == (int)n2.ContentType); Verify((int)n1.Flags == (int)n2.Flags); n1.ContentType = DmdAssemblyContentType.Default; n2.ContentType = AssemblyContentType.Default; Verify((int)n1.ContentType == (int)n2.ContentType); Verify((int)n1.Flags == (int)n2.Flags); n1.ProcessorArchitecture = DmdProcessorArchitecture.IA64; n2.ProcessorArchitecture = ProcessorArchitecture.IA64; Verify((int)n1.ProcessorArchitecture == (int)n2.ProcessorArchitecture); Verify((int)n1.Flags == (int)n2.Flags); n1.ProcessorArchitecture = DmdProcessorArchitecture.Arm; n2.ProcessorArchitecture = ProcessorArchitecture.Arm; Verify((int)n1.ProcessorArchitecture == (int)n2.ProcessorArchitecture); Verify((int)n1.Flags == (int)n2.Flags); n1.Flags = (DmdAssemblyNameFlags)(-1); n2.Flags = (AssemblyNameFlags)(-1); Verify((int)n1.Flags == (int)n2.Flags); Verify((int)n1.ContentType == (int)n2.ContentType); Verify((int)n1.ProcessorArchitecture == (int)n2.ProcessorArchitecture); n1.Flags = 0; n2.Flags = 0; Verify((int)n1.Flags == (int)n2.Flags); Verify((int)n1.ContentType == (int)n2.ContentType); Verify((int)n1.ProcessorArchitecture == (int)n2.ProcessorArchitecture); } static DmdType[] FilterOutTransparentProxy(DmdType[] t2) => t2.Where(a => a.FullName != "System.Runtime.Remoting.Proxies.__TransparentProxy").ToArray(); static DmdType[] FilterOutComObject(DmdAppDomain appDomain, DmdType[] t1) { var comObjType = appDomain.GetWellKnownType(DmdWellKnownType.System___ComObject); return t1.Where(a => (object)a != comObjType).ToArray(); } static void Test(IDmdAssemblyName n1, AssemblyName n2) => Test(n1, n2, true); static void Test(IDmdAssemblyName n1, AssemblyName n2, bool checkProcArch) { Verify(n1.ToString() == n2.ToString()); Verify(n1.Name == n2.Name); Verify(n1.Version == n2.Version); Verify(n1.CultureName == n2.CultureName); Verify((int)n1.Flags == (int)n2.Flags); if (checkProcArch) Verify((int)n1.ProcessorArchitecture == (int)n2.ProcessorArchitecture); Verify((int)n1.ContentType == (int)n2.ContentType); Verify(Equals(n1.GetPublicKey(), n2.GetPublicKey())); Verify(Equals(n1.GetPublicKeyToken(), n2.GetPublicKeyToken())); Verify((int)n1.HashAlgorithm == (int)n2.HashAlgorithm); Verify(n1.FullName == n2.FullName); } static bool Equals(byte[] a, byte[] b) { if (a is null && b is null) return true; if (a is null || b is null) return false; if (a.Length != b.Length) return false; for (int i = 0; i < a.Length; i++) { if (a[i] != b[i]) return false; } return true; } static void Test(DmdModule m1, Module m2) { Verify(m1.ToString() == m2.ToString()); //Verify(m1.FullyQualifiedName == m2.FullyQualifiedName); try { Test(FilterOutTransparentProxy(m1.GetTypes().Skip(1).ToArray()), m2.GetTypes()); } catch (ReflectionTypeLoadException) { Debug.WriteLine($"Couldn't load all types: {m2}"); return; } Verify(m1.ModuleVersionId == m2.ModuleVersionId); Verify(m1.MetadataToken == m2.MetadataToken); Verify(m1.MDStreamVersion == m2.MDStreamVersion); Verify(m1.ScopeName == m2.ScopeName); Verify(m1.Name == m2.Name); Verify(m1.Assembly.GetName().ToString() == m2.Assembly.GetName().ToString()); Test(m1.GetCustomAttributesData(), m2.GetCustomAttributesData()); m1.GetPEKind(out var peKind1, out var machine1); m2.GetPEKind(out var peKind2, out var machine2); if (m1.FullyQualifiedName.IndexOf("GAC", StringComparison.OrdinalIgnoreCase) < 0) Verify((int)peKind1 == (int)peKind2); Verify((int)machine1 == (int)machine2); for (int i = 0; i < bindingFlags1.Length; i++) { Test(m1.GetFields(bindingFlags1[i]), m2.GetFields(bindingFlags2[i])); Test(m1.GetMethods(bindingFlags1[i]), m2.GetMethods(bindingFlags2[i])); } } static void Test(IList t1, Type[] t2) { if (!Verify(t1.Count == t2.Length)) return; for (int i = 0; i < t2.Length; i++) { var t2t = t2[i]; if (t2t is not null) SimpleTest(t1[i], t2t); } } static void Test(IDmdAssemblyName[] n1, AssemblyName[] n2) { if (!Verify(n1.Length == n2.Length)) return; for (int i = 0; i < n1.Length; i++) Test(n1[i], n2[i]); } static void TestModule(DmdModule m1, Module m2) { Verify(m1.Assembly.GetName().ToString() == m2.Assembly.GetName().ToString()); Verify(m1.ScopeName == m2.ScopeName); } static void TestMember(DmdMemberInfo m1, MemberInfo m2) { var m1s = m1.ToString(); bool b = m1s == m2.ToString(); // FnPtr is sometimes written as IntPtr, and other times as (fnptr) if (b || !m1s.Contains("*")) Verify(b); Verify((int)m1.MemberType == (int)m2.MemberType); Verify(m1.Name == m2.Name); bool isGlobal = (m2.MemberType == MemberTypes.Field || m2.MemberType == MemberTypes.Method) && m2.DeclaringType is null; if (isGlobal) { Verify((m1.DeclaringType is not null) == (m2.DeclaringType is null)); Verify((m1.ReflectedType is not null) == (m2.ReflectedType is null)); } else { Verify((m1.DeclaringType is not null) == (m2.DeclaringType is not null)); if (m1.DeclaringType is not null) SimpleTest(m1.DeclaringType, m2.DeclaringType); Verify((m1.ReflectedType is not null) == (m2.ReflectedType is not null)); if (m1.ReflectedType is not null) SimpleTest(m1.ReflectedType, m2.ReflectedType); } Verify(m1.MetadataToken == m2.MetadataToken); TestModule(m1.Module, m2.Module); Test(m1.MemberType == DmdMemberTypes.Constructor ? FilterOutSecurityAttributes(m1.AppDomain, m1.GetCustomAttributesData()) : m1.GetCustomAttributesData(), m2.GetCustomAttributesData()); } static IList FilterOutSecurityAttributes(DmdAppDomain appDomain, IEnumerable c) { var saType = appDomain.GetWellKnownType(DmdWellKnownType.System_Security_Permissions_SecurityAttribute); return c.Where(a => !saType.IsAssignableFrom(a.AttributeType)).ToArray(); } static void TestSameException(Func func1, Func func2, Func compare) { Exception ex1, ex2; T1 t1; T2 t2; try { t1 = func1(); ex1 = null; } catch (Exception ex) { ex1 = ex; t1 = default(T1); } try { t2 = func2(); ex2 = null; } catch (Exception ex) { ex2 = ex; t2 = default(T2); } if (Verify((ex1 is not null) == (ex2 is not null))) { if (ex1 is not null) Verify(ex1.GetType() == ex2.GetType()); else Verify(compare(t1, t2)); } } static void TestTypes(DmdType t1, Type t2) { try { TestTypesCore(t1, t2); } catch (TypeResolveException trex) { Debug.WriteLine($"{t2}: Couldn't resolve a type: {trex.Type}"); } } static void TestTypesCore(DmdType t1, Type t2) { TestMember(t1, t2); Verify((int)t1.MemberType == (int)t2.MemberType); if (TESTEXCEPTIONS || t1.IsGenericParameter) TestSameException(() => t1.DeclaringMethod, () => t2.DeclaringMethod, (a, b) => a?.ToString() == b?.ToString()); Verify(t1.Assembly.ToString() == t2.Assembly.ToString()); Verify(t1.FullName == t2.FullName); Verify(t1.Namespace == t2.Namespace); Verify(t1.AssemblyQualifiedName == t2.AssemblyQualifiedName); TestBaseTypes(t1, t2); Test(t1.StructLayoutAttribute, t2.StructLayoutAttribute); Verify(t1.IsNested == t2.IsNested); if (TESTEXCEPTIONS || t1.IsGenericParameter) TestSameException(() => t1.GenericParameterAttributes, () => t2.GenericParameterAttributes, (a, b) => (int)a == (int)b); if (t1 != t1.AppDomain.GetWellKnownType(DmdWellKnownType.System___ComObject)) Verify(t1.IsVisible == t2.IsVisible); Verify((int)t1.Attributes == (int)t2.Attributes); Verify(t1.IsNotPublic == t2.IsNotPublic); Verify(t1.IsPublic == t2.IsPublic); Verify(t1.IsNestedPublic == t2.IsNestedPublic); Verify(t1.IsNestedPrivate == t2.IsNestedPrivate); Verify(t1.IsNestedFamily == t2.IsNestedFamily); Verify(t1.IsNestedAssembly == t2.IsNestedAssembly); Verify(t1.IsNestedFamANDAssem == t2.IsNestedFamANDAssem); Verify(t1.IsNestedFamORAssem == t2.IsNestedFamORAssem); Verify(t1.IsAutoLayout == t2.IsAutoLayout); Verify(t1.IsLayoutSequential == t2.IsLayoutSequential); Verify(t1.IsExplicitLayout == t2.IsExplicitLayout); Verify(t1.IsClass == t2.IsClass); Verify(t1.IsInterface == t2.IsInterface); Verify(t1.IsValueType == t2.IsValueType); Verify(t1.IsAbstract == t2.IsAbstract); Verify(t1.IsSealed == t2.IsSealed); Verify(t1.IsEnum == t2.IsEnum); Verify(t1.IsSpecialName == t2.IsSpecialName); Verify(t1.IsImport == t2.IsImport); Verify(t1.IsAnsiClass == t2.IsAnsiClass); Verify(t1.IsUnicodeClass == t2.IsUnicodeClass); Verify(t1.IsAutoClass == t2.IsAutoClass); Verify(t1.IsSerializable == t2.IsSerializable); Verify(DmdType.GetTypeCode(t1) == Type.GetTypeCode(t2)); Verify(t1.TypeInitializer?.ToString() == t2.TypeInitializer?.ToString()); Verify(t1.IsArray == t2.IsArray); Verify(t1.IsGenericType == t2.IsGenericType); Verify(t1.IsGenericTypeDefinition == t2.IsGenericTypeDefinition); Verify(t1.IsConstructedGenericType == t2.IsConstructedGenericType); Verify(t1.IsGenericParameter == t2.IsGenericParameter); if (TESTEXCEPTIONS || t1.IsGenericParameter) TestSameException(() => t1.GenericParameterPosition, () => t2.GenericParameterPosition, (a, b) => a == b); Verify(t1.ContainsGenericParameters == t2.ContainsGenericParameters); Verify(t1.IsByRef == t2.IsByRef); Verify(t1.IsPointer == t2.IsPointer); Verify(t1.IsPrimitive == t2.IsPrimitive); Verify(t1.HasElementType == t2.HasElementType); Verify(t1.IsCOMObject == t2.IsCOMObject); Verify(t1.IsContextful == t2.IsContextful); Verify(t1.IsMarshalByRef == t2.IsMarshalByRef); VerifyTypes(t1.GenericTypeArguments, t2.GenericTypeArguments); Test(t1.GetInterfaces(), t2.GetInterfaces()); if (TESTEXCEPTIONS || t1.IsArray) TestSameException(() => t1.GetArrayRank(), () => t2.GetArrayRank(), (a, b) => a == b); if (TESTEXCEPTIONS || t1.IsGenericParameter) TestSameException(() => t1.GetGenericParameterConstraints(), () => t2.GetGenericParameterConstraints(), (a, b) => { Test(a, b); return true; }); SimpleTest(t1.GetElementType(), t2.GetElementType()); Test(t1.GetGenericArguments(), t2.GetGenericArguments()); Test(t1.GenericTypeArguments, t2.GenericTypeArguments); if (TESTEXCEPTIONS || t1.IsGenericType) TestSameException(() => t1.GetGenericTypeDefinition(), () => t2.GetGenericTypeDefinition(), (a, b) => { SimpleTest(a, b); return true; }); if (TESTEXCEPTIONS || t1.IsEnum) TestSameException(() => t1.GetEnumNames(), () => t2.GetEnumNames(), (a, b) => EqualsIgnoreOrder(a, b)); if (TESTEXCEPTIONS || t1.IsEnum) TestSameException(() => t1.GetEnumUnderlyingType(), () => t2.GetEnumUnderlyingType(), (a, b) => { SimpleTest(a, b); return true; }); for (int i = 0; i < bindingFlags1.Length; i++) { Test(t1.GetFields(bindingFlags1[i]), t2.GetFields(bindingFlags2[i])); Test(t1.GetConstructors(bindingFlags1[i]), t2.GetConstructors(bindingFlags2[i])); Test(t1.GetMethods(bindingFlags1[i]), t2.GetMethods(bindingFlags2[i])); Test(t1, t1.GetProperties(bindingFlags1[i]), t2.GetProperties(bindingFlags2[i])); Test(t1.GetEvents(bindingFlags1[i]), t2.GetEvents(bindingFlags2[i])); Test(t1.GetNestedTypes(bindingFlags1[i]), Sort2(t2.GetNestedTypes(bindingFlags2[i]))); SimpleTest(t1.GetMembers(bindingFlags1[i]), t2.GetMembers(bindingFlags2[i])); } SimpleTest(t1.GetConstructors(), t2.GetConstructors()); SimpleTest(t1.GetMethods(), t2.GetMethods()); SimpleTest(t1.GetFields(), t2.GetFields()); SimpleTest(t1.GetEvents(), t2.GetEvents()); SimpleTest(t1.GetProperties(), t2.GetProperties()); SimpleTest(t1.GetNestedTypes(), t2.GetNestedTypes()); SimpleTest(t1.GetMembers(), t2.GetMembers()); SimpleTest(t1.GetDefaultMembers(), t2.GetDefaultMembers()); } static bool EqualsIgnoreOrder(string[] a, string[] b) { if (!Verify(a.Length == b.Length)) return false; Array.Sort(a, StringComparer.Ordinal); Array.Sort(b, StringComparer.Ordinal); for (int i = 0; i < a.Length; i++) { if (a[i] != b[i]) return false; } return true; } static void SimpleTest(DmdMemberInfo[] m1, MemberInfo[] m2) { if (!Verify(m1.Length == m2.Length)) return; Verify( m1.GetType().GetElementType() is var m1t && m2.GetType().GetElementType() is var m2t && ( (m1t == typeof(DmdMemberInfo) && m2t == typeof(MemberInfo)) || (m1t == typeof(DmdType) && m2t == typeof(Type)) || (m1t == typeof(DmdMethodBase) && m2t == typeof(MethodBase)) || (m1t == typeof(DmdMethodInfo) && m2t == typeof(MethodInfo)) || (m1t == typeof(DmdConstructorInfo) && m2t == typeof(ConstructorInfo)) || (m1t == typeof(DmdFieldInfo) && m2t == typeof(FieldInfo)) || (m1t == typeof(DmdPropertyInfo) && m2t == typeof(PropertyInfo)) || (m1t == typeof(DmdEventInfo) && m2t == typeof(EventInfo)) ) ); Sort1(m1); Sort2(m2); for (int i = 0; i < m1.Length; i++) { var a = m1[i]; var b = m2[i]; if (!Verify((int)a.MemberType == (int)b.MemberType)) continue; switch (a.MemberType) { case DmdMemberTypes.Constructor: case DmdMemberTypes.Method: case DmdMemberTypes.Event: case DmdMemberTypes.Field: case DmdMemberTypes.Property: SimpleTest(a, b); break; case DmdMemberTypes.TypeInfo: case DmdMemberTypes.NestedType: SimpleTest((DmdType)a, (Type)b); break; default: Verify(false); break; } } } static void VerifyTypes(IList t1, IList t2) { if (!Verify(t1.Count == t2.Count)) return; for (int i = 0; i < t1.Count; i++) { var a = t1[i]; var b = t2[i]; if (!Verify(a.AssemblyQualifiedName == b.AssemblyQualifiedName || (a.IsMetadataReference && a.ResolveNoThrow() is null && a.FullName == b.FullName))) break; } } static void Test(StructLayoutAttribute a, StructLayoutAttribute b) { if (!Verify((a is null) == (b is null))) return; if (a is null) return; Verify(a.Pack == b.Pack); Verify(a.Size == b.Size); Verify(a.CharSet == b.CharSet); Verify(a.Value == b.Value); } static void TestBaseTypes(DmdType t1, Type t2) { for (;;) { DmdType bt1; try { bt1 = t1.BaseType; } catch (ResolveException) { return; } var bt2 = t2.BaseType; SimpleTest(bt1, bt2); Verify((bt1 is null) == (bt2 is null)); if (bt1 is not null) { if (!Verify(bt1.AssemblyQualifiedName == bt2.AssemblyQualifiedName || (bt1.IsMetadataReference && bt1.ResolveNoThrow() is null && bt1.FullName == bt2.FullName))) break; } if (bt1 is null) break; t1 = bt1; t2 = bt2; } } static T[] Sort1(T[] array) where T : DmdMemberInfo { Array.Sort(array, (a, b) => { var c = a.MetadataToken.CompareTo(b.MetadataToken); if (c != 0) return c; return StringComparer.Ordinal.Compare(a.Name, b.Name); }); return array; } static T[] Sort2(T[] array) where T : MemberInfo { Array.Sort(array, (a, b) => { var c = a.MetadataToken.CompareTo(b.MetadataToken); if (c != 0) return c; return StringComparer.Ordinal.Compare(a.Name, b.Name); }); return array; } static void Test(DmdFieldInfo[] f1, FieldInfo[] f2) { if (!Verify(f1.Length == f2.Length)) return; Sort1(f1); Sort2(f2); for (int i = 0; i < f1.Length; i++) Test(f1[i], f2[i]); } static void Test(DmdMethodBase[] m1, MethodBase[] m2) { if (!Verify(m1.Length == m2.Length)) return; Sort1(m1); Sort2(m2); for (int i = 0; i < m1.Length; i++) Test(m1[i], m2[i]); } static void Test(DmdType t1, DmdPropertyInfo[] p1, PropertyInfo[] p2) { if (!Verify(p1.Length == p2.Length)) return; Sort1(p1); Sort2(p2); for (int i = 0; i < p1.Length; i++) Test(p1[i], p2[i]); } static void Test(DmdEventInfo[] e1, EventInfo[] e2) { if (!Verify(e1.Length == e2.Length)) return; Sort1(e1); Sort2(e2); for (int i = 0; i < e1.Length; i++) Test(e1[i], e2[i]); } static void Test(DmdFieldInfo f1, FieldInfo f2) { TestMember(f1, f2); Test(f1.FieldType, f2.FieldType, f2.DeclaringType); Verify((int)f1.Attributes == (int)f2.Attributes); Verify(f1.IsPublic == f2.IsPublic); Verify(f1.IsPrivate == f2.IsPrivate); Verify(f1.IsFamily == f2.IsFamily); Verify(f1.IsAssembly == f2.IsAssembly); Verify(f1.IsFamilyAndAssembly == f2.IsFamilyAndAssembly); Verify(f1.IsFamilyOrAssembly == f2.IsFamilyOrAssembly); Verify(f1.IsStatic == f2.IsStatic); Verify(f1.IsInitOnly == f2.IsInitOnly); Verify(f1.IsLiteral == f2.IsLiteral); Verify(f1.IsNotSerialized == f2.IsNotSerialized); Verify(f1.IsSpecialName == f2.IsSpecialName); Verify(f1.IsPinvokeImpl == f2.IsPinvokeImpl); if (TESTEXCEPTIONS || (f1.HasDefault && f2.GetType().FullName == "System.Reflection.MdFieldInfo")) { object f2Cons = null; bool ok = true; try { f2Cons = f2.GetRawConstantValue(); } catch (InvalidOperationException) { ok = false; } if (ok) Verify(Equals(f1.GetRawConstantValue(), f2Cons)); } Test(f1.GetRequiredCustomModifiers(), f2.GetRequiredCustomModifiers()); Test(f1.GetOptionalCustomModifiers(), f2.GetOptionalCustomModifiers()); } static void Test(DmdMethodBase m1, MethodBase m2) { TestMember(m1, m2); Verify((int)m1.Attributes == (int)m2.Attributes); Verify((int)m1.MethodImplementationFlags == (int)m2.MethodImplementationFlags); Verify((int)m1.CallingConvention == (int)m2.CallingConvention); Verify(m1.IsGenericMethodDefinition == m2.IsGenericMethodDefinition); Verify(m1.IsGenericMethod == m2.IsGenericMethod); Verify(m1.ContainsGenericParameters == m2.ContainsGenericParameters); Verify(m1.IsPublic == m2.IsPublic); Verify(m1.IsPrivate == m2.IsPrivate); Verify(m1.IsFamily == m2.IsFamily); Verify(m1.IsAssembly == m2.IsAssembly); Verify(m1.IsFamilyAndAssembly == m2.IsFamilyAndAssembly); Verify(m1.IsFamilyOrAssembly == m2.IsFamilyOrAssembly); Verify(m1.IsStatic == m2.IsStatic); Verify(m1.IsFinal == m2.IsFinal); Verify(m1.IsVirtual == m2.IsVirtual); Verify(m1.IsHideBySig == m2.IsHideBySig); Verify(m1.IsAbstract == m2.IsAbstract); Verify(m1.IsSpecialName == m2.IsSpecialName); Verify(m1.IsConstructor == m2.IsConstructor); Test(m1.GetParameters(), m2.GetParameters()); if (TESTEXCEPTIONS || m1 is DmdMethodInfo) TestSameException(() => m1.GetGenericArguments(), () => m2.GetGenericArguments(), (a, b) => { Test(a, b); return true; }); Test(m1, m2, m1.GetMethodBody(), m2.GetMethodBody(), m2.DeclaringType); if (m1 is DmdMethodInfo) { var mi1 = (DmdMethodInfo)m1; var mi2 = (MethodInfo)m2; Test(mi1.ReturnParameter, mi2.ReturnParameter); Test(mi1.ReturnType, mi2.ReturnType, mi2.DeclaringType); Verify(((object)mi1.ReturnTypeCustomAttributes == mi1.ReturnParameter) == ((object)mi2.ReturnTypeCustomAttributes == mi2.ReturnParameter)); SimpleTest(mi1.GetBaseDefinition(), mi2.GetBaseDefinition()); if (TESTEXCEPTIONS || m1.IsGenericMethod) TestSameException(() => mi1.GetGenericMethodDefinition(), () => mi2.GetGenericMethodDefinition(), (a, b) => { SimpleTest(a, b); return true; }); } } static void Test(DmdMethodBase m1, MethodBase m2, DmdMethodBody b1, MethodBody b2, Type declaringType2) { if (!Verify((b1 is null) == (b2 is null))) return; if (b1 is null) return; Verify((b1.ToString() == b1.GetType().ToString()) == (b2.ToString() == b2.GetType().ToString())); Verify(b1.LocalSignatureMetadataToken == b2.LocalSignatureMetadataToken); Test(b1.LocalVariables, b2.LocalVariables, declaringType2); Verify(b1.MaxStackSize == b2.MaxStackSize); Verify(b1.InitLocals == b2.InitLocals); TestInstructions(m1, m2, b1.GetILAsByteArray(), b2.GetILAsByteArray()); Test(b1.ExceptionHandlingClauses, b2.ExceptionHandlingClauses); } static void TestInstructions(DmdMethodBase m1, MethodBase m2, byte[] a1, byte[] a2) { if (!Equals(a1, a2)) return; var module1 = m1.Module; var module2 = m2.Module; IList gta1, gma1; Type[] gta2, gma2; gta1 = m1.DeclaringType.GetGenericArguments(); gta2 = m2.DeclaringType?.GetGenericArguments().ToArray(); if (m1 is DmdMethodInfo mi1) gma1 = mi1.GetGenericArguments(); else gma1 = null; if (m2 is MethodInfo mi2) gma2 = mi2.GetGenericArguments().ToArray(); else gma2 = null; int pos = 0; int token; while (pos < a1.Length) { var opc = ReadOpCode(a1, ref pos); switch (opc.OperandType) { case DNE.OperandType.InlineNone: case DNE.OperandType.InlinePhi: break; case DNE.OperandType.ShortInlineVar: case DNE.OperandType.ShortInlineBrTarget: case DNE.OperandType.ShortInlineI: pos++; break; case DNE.OperandType.InlineVar: pos += 2; break; case DNE.OperandType.InlineBrTarget: case DNE.OperandType.InlineI: case DNE.OperandType.ShortInlineR: pos += 4; break; case DNE.OperandType.InlineI8: case DNE.OperandType.InlineR: pos += 8; break; case DNE.OperandType.InlineSwitch: int count = BitConverter.ToInt32(a1, pos); pos += 4 + count * 4; break; case DNE.OperandType.InlineString: token = BitConverter.ToInt32(a1, pos); pos += 4; Verify(module1.ResolveString(token) == module2.ResolveString(token)); break; case DNE.OperandType.InlineType: case DNE.OperandType.InlineField: case DNE.OperandType.InlineMethod: case DNE.OperandType.InlineTok: token = BitConverter.ToInt32(a1, pos); pos += 4; switch ((Table)(token >> 24)) { case Table.TypeRef: case Table.TypeDef: case Table.TypeSpec: try { var t1 = module1.ResolveType(token, gta1, gma1); var t2 = module2.ResolveType(token, gta2, gma2); FixTypes(ref t1, t2, m2.DeclaringType); SimpleTest(t1, t2); } catch (ResolveException) { } catch (FileLoadException) { } break; case Table.Field: case Table.Method: case Table.MethodSpec: case Table.MemberRef: try { var memb1 = module1.ResolveMember(token, gta1, gma1); var memb2 = module2.ResolveMember(token, gta2, gma2); FixReflectedType(ref memb1, memb2); SimpleTest(memb1, memb2); } catch (ResolveException) { } catch (FileLoadException) { } break; } break; case DNE.OperandType.InlineSig: token = BitConverter.ToInt32(a1, pos); pos += 4; try { var s1 = module1.ResolveSignature(token); var s2 = module2.ResolveSignature(token); Verify(Equals(s1, s2)); } catch (ResolveException) { } catch (FileLoadException) { } break; default: throw new InvalidOperationException("Invalid OpCode.OperandType"); } } } static void FixReflectedType(ref DmdMemberInfo memb1, MemberInfo memb2) { if (memb2.ReflectedType != memb2.DeclaringType) return; if (memb1.ReflectedType == memb1.DeclaringType) return; if (memb1 is DmdMethodBase && memb2 is MethodBase) { memb1 = memb1.DeclaringType.GetMethod(memb1.DeclaringType.Module, memb1.MetadataToken, throwOnError: true); return; } if (memb1 is DmdFieldInfo && memb2 is FieldInfo) { memb1 = memb1.DeclaringType.GetField(memb1.DeclaringType.Module, memb1.MetadataToken, throwOnError: true); return; } } static DNE.OpCode ReadOpCode(byte[] a, ref int pos) { var op = a[pos++]; if (op != 0xFE) return DNE.OpCodes.OneByteOpCodes[op]; return DNE.OpCodes.TwoByteOpCodes[a[pos++]]; } static void Test(IList l1, IList l2, Type declaringType2) { Verify(l1 is ReadOnlyCollection); Verify(l2 is ReadOnlyCollection); if (!Verify(l1.Count == l2.Count)) return; for (int i = 0; i < l1.Count; i++) Test(l1[i], l2[i], declaringType2); } static void Test(DmdLocalVariableInfo l1, LocalVariableInfo l2, Type declaringType2) { var l1s = l1.ToString(); Verify(l1s == l2.ToString() || l1s.Contains("*")); Test(l1.LocalType, l2.LocalType, declaringType2); Verify(l1.IsPinned == l2.IsPinned); Verify(l1.LocalIndex == l2.LocalIndex); } static void Test(IList e1, IList e2) { Verify(e1 is ReadOnlyCollection); Verify(e2 is ReadOnlyCollection); if (!Verify(e1.Count == e2.Count)) return; for (int i = 0; i < e1.Count; i++) Test(e1[i], e2[i]); } static void Test(DmdExceptionHandlingClause e1, ExceptionHandlingClause e2) { Verify(e1.ToString() == e2.ToString()); Verify((int)e1.Flags == (int)e2.Flags); Verify(e1.TryOffset == e2.TryOffset); Verify(e1.TryLength == e2.TryLength); Verify(e1.HandlerOffset == e2.HandlerOffset); Verify(e1.HandlerLength == e2.HandlerLength); if (TESTEXCEPTIONS || e1.Flags == DmdExceptionHandlingClauseOptions.Filter) TestSameException(() => e1.FilterOffset, () => e2.FilterOffset, (a, b) => a == b); if (TESTEXCEPTIONS || e1.Flags == DmdExceptionHandlingClauseOptions.Clause) TestSameException(() => e1.CatchType, () => e2.CatchType, (a, b) => { SimpleTest(a, b); return true; }); } static void Test(DmdPropertyInfo p1, PropertyInfo p2) { TestMember(p1, p2); Test(p1.PropertyType, p2.PropertyType, p2.DeclaringType); Verify((int)p1.Attributes == (int)p2.Attributes); Verify(p1.IsSpecialName == p2.IsSpecialName); Verify(p1.CanRead == p2.CanRead); Verify(p1.CanWrite == p2.CanWrite); if (TESTEXCEPTIONS || p1.HasDefault) { object f2Cons = null; bool ok = true; try { f2Cons = p2.GetRawConstantValue(); } catch (InvalidOperationException) { ok = false; } if (ok) Verify(Equals(p1.GetRawConstantValue(), f2Cons)); } SimpleTest(p1.GetAccessors(false), p2.GetAccessors(false)); SimpleTest(p1.GetAccessors(true), p2.GetAccessors(true)); SimpleTest(p1.GetGetMethod(false), p2.GetGetMethod(false)); SimpleTest(p1.GetGetMethod(true), p2.GetGetMethod(true)); SimpleTest(p1.GetSetMethod(false), p2.GetSetMethod(false)); SimpleTest(p1.GetSetMethod(true), p2.GetSetMethod(true)); Test(p1.GetIndexParameters(), p2.GetIndexParameters()); Test(p1.GetRequiredCustomModifiers(), p2.GetRequiredCustomModifiers()); Test(p1.GetOptionalCustomModifiers(), p2.GetOptionalCustomModifiers()); SimpleTest(p1.GetAccessors(), p2.GetAccessors()); SimpleTest(p1.GetMethod, p2.GetMethod); SimpleTest(p1.SetMethod, p2.SetMethod); SimpleTest(p1.GetGetMethod(), p2.GetGetMethod()); SimpleTest(p1.GetSetMethod(), p2.GetSetMethod()); } static void SimpleTest(DmdMemberInfo m1, MemberInfo m2) { if (!Verify((m1 is null) == (m2 is null))) return; if (m1 is null) return; var m1s = m1.ToString(); bool b = m1s == m2.ToString(); Verify(b || m1s.Contains("*")); Verify(m1.MetadataToken == m2.MetadataToken); if (m2.ReflectedType is not null) Test(m1.ReflectedType, m2.ReflectedType, m2.DeclaringType); if (m2.DeclaringType is not null) Test(m1.DeclaringType, m2.DeclaringType, m2.DeclaringType); } static void Test(DmdEventInfo e1, EventInfo e2) { TestMember(e1, e2); Verify((int)e1.Attributes == (int)e2.Attributes); Verify(e1.IsSpecialName == e2.IsSpecialName); Test(e1.EventHandlerType, e2.EventHandlerType, e2.DeclaringType); Verify(e1.IsMulticast == e2.IsMulticast); SimpleTest(e1.AddMethod, e2.AddMethod); SimpleTest(e1.RemoveMethod, e2.RemoveMethod); SimpleTest(e1.RaiseMethod, e2.RaiseMethod); SimpleTest(e1.GetOtherMethods(), e2.GetOtherMethods()); SimpleTest(e1.GetAddMethod(), e2.GetAddMethod()); SimpleTest(e1.GetRemoveMethod(), e2.GetRemoveMethod()); SimpleTest(e1.GetRaiseMethod(), e2.GetRaiseMethod()); SimpleTest(e1.GetOtherMethods(false), e2.GetOtherMethods(false)); SimpleTest(e1.GetOtherMethods(true), e2.GetOtherMethods(true)); SimpleTest(e1.GetAddMethod(false), e2.GetAddMethod(false)); SimpleTest(e1.GetAddMethod(true), e2.GetAddMethod(true)); SimpleTest(e1.GetRemoveMethod(false), e2.GetRemoveMethod(false)); SimpleTest(e1.GetRemoveMethod(true), e2.GetRemoveMethod(true)); SimpleTest(e1.GetRaiseMethod(false), e2.GetRaiseMethod(false)); SimpleTest(e1.GetRaiseMethod(true), e2.GetRaiseMethod(true)); } static void Test(IList cas1, IList cas2) { if (!Verify(cas1.Count == cas2.Count)) return; cas1 = Sort1(cas1); cas2 = Sort2(cas2); for (int i = 0; i < cas1.Count; i++) Test(cas1[i], cas2[i]); } static IList Sort1(IList input) { var list = new List(input); list.Sort((a, b) => { int c = a.AttributeType.FullName.CompareTo(b.AttributeType.FullName); if (c != 0) return c; c = a.ConstructorArguments.Count - b.ConstructorArguments.Count; if (c != 0) return c; c = a.NamedArguments.Count - b.NamedArguments.Count; if (c != 0) return c; for (int i = 0; i < a.ConstructorArguments.Count; i++) { c = a.ConstructorArguments[i].ToString().CompareTo(b.ConstructorArguments[i].ToString()); if (c != 0) return c; } for (int i = 0; i < a.NamedArguments.Count; i++) { c = a.NamedArguments[i].ToString().CompareTo(b.NamedArguments[i].ToString()); if (c != 0) return c; } return 0; }); return list; } static IList Sort2(IList input) { var list = new List(input); list.Sort((a, b) => { int c = a.AttributeType.FullName.CompareTo(b.AttributeType.FullName); if (c != 0) return c; c = a.ConstructorArguments.Count - b.ConstructorArguments.Count; if (c != 0) return c; c = a.NamedArguments.Count - b.NamedArguments.Count; if (c != 0) return c; for (int i = 0; i < a.ConstructorArguments.Count; i++) { c = a.ConstructorArguments[i].ToString().CompareTo(b.ConstructorArguments[i].ToString()); if (c != 0) return c; } for (int i = 0; i < a.NamedArguments.Count; i++) { c = a.NamedArguments[i].ToString().CompareTo(b.NamedArguments[i].ToString()); if (c != 0) return c; } return 0; }); return list; } static void TestTypeSpecs(DmdType t1, Type t2) { TestTypes(t1, t2); TestTypes(t1.MakeByRefType(), t2.MakeByRefType()); TestTypes(t1.MakePointerType(), t2.MakePointerType()); TestTypes(t1.MakeArrayType(), t2.MakeArrayType()); TestTypes(t1.MakeArrayType(1), t2.MakeArrayType(1)); TestTypes(t1.MakeArrayType(2), t2.MakeArrayType(2)); TestTypes(t1.MakeArrayType(32), t2.MakeArrayType(32)); TestTypes(t1.MakeArrayType().MakePointerType(), t2.MakeArrayType().MakePointerType()); TestTypes(t1.MakeArrayType(1).MakePointerType(), t2.MakeArrayType(1).MakePointerType()); TestTypes(t1.MakeArrayType(2).MakePointerType(), t2.MakeArrayType(2).MakePointerType()); TestTypes(t1.MakeArrayType(32).MakePointerType(), t2.MakeArrayType(32).MakePointerType()); TestTypes(t1.MakePointerType().MakeByRefType(), t2.MakePointerType().MakeByRefType()); TestTypes(t1.MakeArrayType().MakeByRefType(), t2.MakeArrayType().MakeByRefType()); TestTypes(t1.MakeArrayType(1).MakeByRefType(), t2.MakeArrayType(1).MakeByRefType()); TestTypes(t1.MakeArrayType(2).MakeByRefType(), t2.MakeArrayType(2).MakeByRefType()); TestTypes(t1.MakeArrayType(32).MakeByRefType(), t2.MakeArrayType(32).MakeByRefType()); TestTypes(t1.MakeArrayType().MakePointerType().MakeByRefType(), t2.MakeArrayType().MakePointerType().MakeByRefType()); TestTypes(t1.MakeArrayType(1).MakePointerType().MakeByRefType(), t2.MakeArrayType(1).MakePointerType().MakeByRefType()); TestTypes(t1.MakeArrayType(2).MakePointerType().MakeByRefType(), t2.MakeArrayType(2).MakePointerType().MakeByRefType()); TestTypes(t1.MakeArrayType(32).MakePointerType().MakeByRefType(), t2.MakeArrayType(32).MakePointerType().MakeByRefType()); } static void FixTypes(ref DmdType t1, Type t2, Type declaringType2) { try { if (t1.IsByRef) { if (t2.IsByRef) { var t1e = t1.GetElementType(); var t2e = t2.GetElementType(); if (t1e.IsConstructedGenericType && t2e.IsGenericTypeDefinition) t1 = t1e.GetGenericTypeDefinition().MakeByRefType(); } } else if (t1.IsPointer) { if (t2.IsPointer) { var t1e = t1.GetElementType(); var t2e = t2.GetElementType(); if (t1e.IsConstructedGenericType && t2e.IsGenericTypeDefinition) t1 = t1e.GetGenericTypeDefinition().MakePointerType(); } } else if (t1.IsArray) { if (t2.IsArray) { int rank = t2.GetArrayRank(); var t1e = t1.GetElementType(); var t2e = t2.GetElementType(); if (t1e.IsConstructedGenericType && t2e.IsGenericTypeDefinition) t1 = rank == 1 ? t1e.GetGenericTypeDefinition().MakeArrayType() : t1e.GetGenericTypeDefinition().MakeArrayType(rank); } } else { if (t1.IsConstructedGenericType && t2.IsGenericTypeDefinition) t1 = t1.GetGenericTypeDefinition(); } } catch (ResolveException) { } } static void Test(DmdType t1, Type t2, Type declaringType2) { FixTypes(ref t1, t2, declaringType2); SimpleTest(t1, t2); } static void SimpleTest(DmdType t1, Type t2) { if (!Verify((t1 is null) == (t2 is null))) return; if (t1 is null) return; Verify((int)t1.MemberType == (int)t2.MemberType); try { var t1s = t1.ToString(); bool b = t1s == t2.ToString(); // FnPtr is sometimes written as IntPtr, and other times as (fnptr) if (b || !t1s.Contains("*")) { Verify(b); Verify(t1.AssemblyQualifiedName == t2.AssemblyQualifiedName || (t1.IsMetadataReference && t1.ResolveNoThrow() is null && t1.FullName == t2.FullName)); Verify(t1.FullName == t2.FullName); Verify(t1.Name == t2.Name); } Verify(t1.IsGenericType == t2.IsGenericType); Verify(t1.IsGenericTypeDefinition == t2.IsGenericTypeDefinition); } catch (ResolveException) { } } static void Test(DmdCustomAttributeData ca1, CustomAttributeData ca2) { Verify(ca1.ToString() == ca2.ToString()); SimpleTest(ca1.AttributeType, ca2.AttributeType); Verify(ca1.Constructor.ToString() == ca2.Constructor.ToString()); Test(ca1.ConstructorArguments, ca2.ConstructorArguments); Test(ca1.NamedArguments, ca2.NamedArguments); } static void Test(IList args1, IList args2) { if (!Verify(args1.Count == args2.Count)) return; for (int i = 0; i < args1.Count; i++) Test(args1[i], args2[i]); } static void Test(IList args1, IList args2) { if (!Verify(args1.Count == args2.Count)) return; for (int i = 0; i < args1.Count; i++) Test(args1[i], args2[i]); } static void Test(DmdCustomAttributeTypedArgument arg1, CustomAttributeTypedArgument arg2) { Verify(arg1.ToString() == arg2.ToString()); SimpleTest(arg1.ArgumentType, arg2.ArgumentType); if (arg1.Value is ReadOnlyCollection ar1 && arg2.Value is ReadOnlyCollection ar2) { if (!Verify(ar1.Count == ar2.Count)) return; Test(ar1, ar2); } else Verify(arg1.Value?.ToString() == arg2.Value?.ToString()); } static void Test(DmdCustomAttributeNamedArgument arg1, CustomAttributeNamedArgument arg2) { Verify(arg1.ToString() == arg2.ToString()); Verify(arg1.MemberInfo.ToString() == arg2.MemberInfo.ToString()); Verify(arg1.MemberName == arg2.MemberName); Verify(arg1.IsField == arg2.IsField); Test(arg1.TypedValue, arg2.TypedValue); } static void Test(ReadOnlyCollection p1, ParameterInfo[] p2) { if (!Verify(p1.Count == p2.Length)) return; for (int i = 0; i < p1.Count; i++) Test(p1[i], p2[i]); } static void Test(DmdParameterInfo p1, ParameterInfo p2) { var p1s = p1.ToString(); Verify(p1s == p2.ToString() || p1s.Contains("*")); Test(p1.ParameterType, p2.ParameterType, p2.Member.DeclaringType); Verify(p1.Name == p2.Name); Verify(p1.HasDefaultValue == p2.HasDefaultValue); Verify((p1.RawDefaultValue is null && p2.RawDefaultValue == DBNull.Value) || (p1.RawDefaultValue is null && p2.RawDefaultValue == Missing.Value && p1.IsOptional) || Equals(p1.RawDefaultValue, p2.RawDefaultValue)); Verify(p1.Position == p2.Position); Verify((int)p1.Attributes == (int)p2.Attributes); SimpleTest(p1.Member, p2.Member); Verify(p1.MetadataToken == p2.MetadataToken); Test(p1.GetRequiredCustomModifiers(), p2.GetRequiredCustomModifiers()); Test(p1.GetOptionalCustomModifiers(), p2.GetOptionalCustomModifiers()); Test(p1.GetCustomAttributesData(), p2.GetCustomAttributesData()); } } }