From cd86a5bd9c3f687b006e36583b6aa6bab8245c7e Mon Sep 17 00:00:00 2001 From: Buyaa Namnan Date: Thu, 18 Jan 2024 10:34:52 -0800 Subject: [PATCH 1/8] Add public APIs for persisted AssemblyBuilder --- .../Reflection/Emit/RuntimeAssemblyBuilder.cs | 2 + .../System/Reflection/Emit/AssemblyBuilder.cs | 52 +++++++++++++++++++ .../ref/System.Reflection.Emit.cs | 4 ++ .../ILLink.Descriptors.LibraryBuild.xml | 5 +- .../Reflection/Emit/AssemblyBuilderImpl.cs | 18 +------ ...iCompatBaseline.NetCoreAppLatestStable.xml | 20 ++++++- 6 files changed, 81 insertions(+), 20 deletions(-) diff --git a/src/coreclr/System.Private.CoreLib/src/System/Reflection/Emit/RuntimeAssemblyBuilder.cs b/src/coreclr/System.Private.CoreLib/src/System/Reflection/Emit/RuntimeAssemblyBuilder.cs index fa3bfd25dac2f8..c07fc514b9caaf 100644 --- a/src/coreclr/System.Private.CoreLib/src/System/Reflection/Emit/RuntimeAssemblyBuilder.cs +++ b/src/coreclr/System.Private.CoreLib/src/System/Reflection/Emit/RuntimeAssemblyBuilder.cs @@ -299,5 +299,7 @@ protected override void SetCustomAttributeCore(ConstructorInfo con, ReadOnlySpan binaryAttribute); } } + + protected override void SaveCore(Stream stream) => throw new NotSupportedException(); } } diff --git a/src/libraries/System.Private.CoreLib/src/System/Reflection/Emit/AssemblyBuilder.cs b/src/libraries/System.Private.CoreLib/src/System/Reflection/Emit/AssemblyBuilder.cs index d7ee53669cc91b..812609599f273a 100644 --- a/src/libraries/System.Private.CoreLib/src/System/Reflection/Emit/AssemblyBuilder.cs +++ b/src/libraries/System.Private.CoreLib/src/System/Reflection/Emit/AssemblyBuilder.cs @@ -1,6 +1,7 @@ // Licensed to the .NET Foundation under one or more agreements. // The .NET Foundation licenses this file to you under the MIT license. +using System.Collections.Generic; using System.Diagnostics.CodeAnalysis; using System.IO; using System.Runtime.CompilerServices; @@ -32,8 +33,59 @@ public ModuleBuilder DefineDynamicModule(string name) return GetDynamicModuleCore(name); } + /// + /// Defines an that can be saved to a file or stream. + /// + /// The name of the assembly. + /// The assembly that denotes the "system assembly" that houses the well-known types such as + /// A collection that contains the attributes of the assembly. + /// An that can be persisted. + /// The or or is null. + /// Currently the persisted assembly doesn't support running, need to save it and load back to run. + public static AssemblyBuilder DefinePersistedAssembly(AssemblyName name, Assembly coreAssembly, IEnumerable? assemblyAttributes = null) + { + ArgumentNullException.ThrowIfNull(name); + ArgumentNullException.ThrowIfNull(coreAssembly); + + Type? assemblyType = Type.GetType("System.Reflection.Emit.AssemblyBuilderImpl, System.Reflection.Emit", throwOnError: true); + + if (assemblyType == null) + { + throw new TypeLoadException(SR.Format(SR.TypeLoad_TypeNotFound, "System.Reflection.Emit.AssemblyBuilderImpl")); + } + + ConstructorInfo con = assemblyType.GetConstructor(BindingFlags.NonPublic | BindingFlags.Instance, [typeof(AssemblyName), typeof(Assembly), typeof(IEnumerable)])!; + return (AssemblyBuilder)con.Invoke([name, coreAssembly, assemblyAttributes]); + } + protected abstract ModuleBuilder? GetDynamicModuleCore(string name); + /// + /// Serializes the assembly to stream. + /// + /// The stream to which the assembly serialized. + /// is null + public void Save(Stream stream) => SaveCore(stream); + + /// + /// Saves the assembly to disk. + /// + /// The file name of the assembly. + /// is null + public void Save(string assemblyFileName) + { + ArgumentNullException.ThrowIfNull(assemblyFileName); + + using var peStream = new FileStream(assemblyFileName, FileMode.Create, FileAccess.Write); + SaveCore(peStream); + } + + /// + /// When implemented in derived type serializer the assembly to stream. + /// + /// The stream to which the assembly serialized. + protected abstract void SaveCore(Stream stream); + public void SetCustomAttribute(ConstructorInfo con, byte[] binaryAttribute) { ArgumentNullException.ThrowIfNull(con); diff --git a/src/libraries/System.Reflection.Emit/ref/System.Reflection.Emit.cs b/src/libraries/System.Reflection.Emit/ref/System.Reflection.Emit.cs index 7d55329ba942f3..645265fedd2171 100644 --- a/src/libraries/System.Reflection.Emit/ref/System.Reflection.Emit.cs +++ b/src/libraries/System.Reflection.Emit/ref/System.Reflection.Emit.cs @@ -24,6 +24,7 @@ protected AssemblyBuilder() { } public static System.Reflection.Emit.AssemblyBuilder DefineDynamicAssembly(System.Reflection.AssemblyName name, System.Reflection.Emit.AssemblyBuilderAccess access) { throw null; } [System.Diagnostics.CodeAnalysis.RequiresDynamicCode("Defining a dynamic assembly requires dynamic code.")] public static System.Reflection.Emit.AssemblyBuilder DefineDynamicAssembly(System.Reflection.AssemblyName name, System.Reflection.Emit.AssemblyBuilderAccess access, System.Collections.Generic.IEnumerable? assemblyAttributes) { throw null; } + public static System.Reflection.Emit.AssemblyBuilder DefinePersistedAssembly(System.Reflection.AssemblyName name, System.Reflection.Assembly coreAssembly, System.Collections.Generic.IEnumerable? assemblyAttributes = null) { throw null; } public System.Reflection.Emit.ModuleBuilder DefineDynamicModule(string name) { throw null; } protected abstract System.Reflection.Emit.ModuleBuilder DefineDynamicModuleCore(string name); public override bool Equals(object? obj) { throw null; } @@ -54,6 +55,9 @@ protected AssemblyBuilder() { } [System.Diagnostics.CodeAnalysis.RequiresUnreferencedCodeAttribute("Types might be removed by trimming. If the type name is a string literal, consider using Type.GetType instead.")] public override System.Type? GetType(string name, bool throwOnError, bool ignoreCase) { throw null; } public override bool IsDefined(System.Type attributeType, bool inherit) { throw null; } + public void Save(string assemblyFileName) { throw null; } + public void Save(System.IO.Stream stream) { throw null; } + protected abstract void SaveCore(System.IO.Stream stream); public void SetCustomAttribute(System.Reflection.ConstructorInfo con, byte[] binaryAttribute) { } public void SetCustomAttribute(System.Reflection.Emit.CustomAttributeBuilder customBuilder) { } protected abstract void SetCustomAttributeCore(System.Reflection.ConstructorInfo con, System.ReadOnlySpan binaryAttribute); diff --git a/src/libraries/System.Reflection.Emit/src/ILLink/ILLink.Descriptors.LibraryBuild.xml b/src/libraries/System.Reflection.Emit/src/ILLink/ILLink.Descriptors.LibraryBuild.xml index 4ac5a6f3584506..8cf11ab4c01f72 100644 --- a/src/libraries/System.Reflection.Emit/src/ILLink/ILLink.Descriptors.LibraryBuild.xml +++ b/src/libraries/System.Reflection.Emit/src/ILLink/ILLink.Descriptors.LibraryBuild.xml @@ -1,9 +1,8 @@ - - - + + diff --git a/src/libraries/System.Reflection.Emit/src/System/Reflection/Emit/AssemblyBuilderImpl.cs b/src/libraries/System.Reflection.Emit/src/System/Reflection/Emit/AssemblyBuilderImpl.cs index 8f252ace10fd7a..215745a5048284 100644 --- a/src/libraries/System.Reflection.Emit/src/System/Reflection/Emit/AssemblyBuilderImpl.cs +++ b/src/libraries/System.Reflection.Emit/src/System/Reflection/Emit/AssemblyBuilderImpl.cs @@ -19,10 +19,8 @@ internal sealed class AssemblyBuilderImpl : AssemblyBuilder internal List? _customAttributes; - internal AssemblyBuilderImpl(AssemblyName name, Assembly coreAssembly, IEnumerable? assemblyAttributes) + internal AssemblyBuilderImpl(AssemblyName name, Assembly coreAssembly, IEnumerable? assemblyAttributes = null) { - ArgumentNullException.ThrowIfNull(name); - name = (AssemblyName)name.Clone(); ArgumentException.ThrowIfNullOrEmpty(name.Name, "AssemblyName.Name"); @@ -40,10 +38,6 @@ internal AssemblyBuilderImpl(AssemblyName name, Assembly coreAssembly, IEnumerab } } - internal static AssemblyBuilderImpl DefinePersistedAssembly(AssemblyName name, Assembly coreAssembly, - IEnumerable? assemblyAttributes) - => new AssemblyBuilderImpl(name, coreAssembly, assemblyAttributes); - private void WritePEImage(Stream peStream, BlobBuilder ilBuilder) { var peHeaderBuilder = new PEHeaderBuilder( @@ -63,7 +57,7 @@ private void WritePEImage(Stream peStream, BlobBuilder ilBuilder) peBlob.WriteContentTo(peStream); } - internal void Save(Stream stream) + protected override void SaveCore(Stream stream) { ArgumentNullException.ThrowIfNull(stream); @@ -101,14 +95,6 @@ internal void Save(Stream stream) private static AssemblyFlags AddContentType(AssemblyFlags flags, AssemblyContentType contentType) => (AssemblyFlags)((int)contentType << 9) | flags; - internal void Save(string assemblyFileName) - { - ArgumentNullException.ThrowIfNull(assemblyFileName); - - using var peStream = new FileStream(assemblyFileName, FileMode.Create, FileAccess.Write); - Save(peStream); - } - protected override ModuleBuilder DefineDynamicModuleCore(string name) { if (_module != null) diff --git a/src/libraries/apicompat/ApiCompatBaseline.NetCoreAppLatestStable.xml b/src/libraries/apicompat/ApiCompatBaseline.NetCoreAppLatestStable.xml index 05317adadabbfe..2e447a8ee7ad3c 100644 --- a/src/libraries/apicompat/ApiCompatBaseline.NetCoreAppLatestStable.xml +++ b/src/libraries/apicompat/ApiCompatBaseline.NetCoreAppLatestStable.xml @@ -1,4 +1,22 @@  - + + CP0005 + M:System.Reflection.Emit.AssemblyBuilder.SaveCore(System.IO.Stream) + net8.0/mscorlib.dll + net9.0/mscorlib.dll + + + CP0005 + M:System.Reflection.Emit.AssemblyBuilder.SaveCore(System.IO.Stream) + net8.0/netstandard.dll + net9.0/netstandard.dll + + + CP0005 + M:System.Reflection.Emit.AssemblyBuilder.SaveCore(System.IO.Stream) + net8.0/System.Reflection.Emit.dll + net9.0/System.Reflection.Emit.dll + + \ No newline at end of file From 0dc5f1230b58c43f356a6dc690a2a481c751e2a5 Mon Sep 17 00:00:00 2001 From: Buyaa Namnan Date: Thu, 18 Jan 2024 11:55:33 -0800 Subject: [PATCH 2/8] Update tests to use public API, refactor tests so that the temp files deleted --- .../AssemblySaveAssemblyBuilder.cs | 10 +- .../AssemblySaveConstructorBuilderTests.cs | 49 +- .../AssemblySaveCustomAttributeTests.cs | 426 +++--- .../AssemblySaveEnumBuilderTests.cs | 87 +- .../AssemblySaveEventBuilderTests.cs | 39 +- .../AssemblySaveILGeneratorTests.cs | 1155 +++++++++-------- .../AssemblySaveMethodBuilderTests.cs | 79 +- .../AssemblySavePropertyBuilderTests.cs | 110 +- .../AssemblySaveTools.cs | 35 +- .../AssemblySaveTypeBuilderTests.cs | 393 +++--- .../RegexAssemblyCompiler.cs | 13 +- 11 files changed, 1267 insertions(+), 1129 deletions(-) diff --git a/src/libraries/System.Reflection.Emit/tests/PersistableAssemblyBuilder/AssemblySaveAssemblyBuilder.cs b/src/libraries/System.Reflection.Emit/tests/PersistableAssemblyBuilder/AssemblySaveAssemblyBuilder.cs index 96016fddcab86a..e1613be52af895 100644 --- a/src/libraries/System.Reflection.Emit/tests/PersistableAssemblyBuilder/AssemblySaveAssemblyBuilder.cs +++ b/src/libraries/System.Reflection.Emit/tests/PersistableAssemblyBuilder/AssemblySaveAssemblyBuilder.cs @@ -34,7 +34,7 @@ public void AssemblyWithDifferentTypes() aName.CultureInfo = new CultureInfo("en"); aName.Flags = AssemblyNameFlags.Retargetable; - AssemblyBuilder ab = AssemblySaveTools.PopulateAssemblyBuilderAndSaveMethod(aName, null, typeof(string), out MethodInfo saveMethod); + AssemblyBuilder ab = AssemblySaveTools.PopulateAssemblyBuilder(aName); ab.SetCustomAttribute(new CustomAttributeBuilder(typeof(AssemblyDelaySignAttribute).GetConstructor([typeof(bool)]), [true])); @@ -213,10 +213,12 @@ public void AssemblyWithDifferentTypes() eventb.SetRemoveOnMethod(mbRemove); tbEvents.CreateType(); - saveMethod.Invoke(ab, [file.Path]); + ab.Save(file.Path); - Assembly assemblyFromDisk = AssemblySaveTools.LoadAssemblyFromPath(file.Path); - CheckAssembly(assemblyFromDisk); + using (MetadataLoadContext mlc = new MetadataLoadContext(new CoreMetadataAssemblyResolver())) + { + CheckAssembly(mlc.LoadFromAssemblyPath(file.Path)); + } } } diff --git a/src/libraries/System.Reflection.Emit/tests/PersistableAssemblyBuilder/AssemblySaveConstructorBuilderTests.cs b/src/libraries/System.Reflection.Emit/tests/PersistableAssemblyBuilder/AssemblySaveConstructorBuilderTests.cs index 7b7a15bde56854..a3c936bcd5e3b4 100644 --- a/src/libraries/System.Reflection.Emit/tests/PersistableAssemblyBuilder/AssemblySaveConstructorBuilderTests.cs +++ b/src/libraries/System.Reflection.Emit/tests/PersistableAssemblyBuilder/AssemblySaveConstructorBuilderTests.cs @@ -16,7 +16,7 @@ public void DefineConstructorsTest() { using (TempFile file = TempFile.Create()) { - AssemblyBuilder ab = AssemblySaveTools.PopulateAssemblyBuilderTypeBuilderAndSaveMethod(out TypeBuilder type, out MethodInfo saveMethod); + AssemblyBuilder ab = AssemblySaveTools.PopulateAssemblyBuilderAndTypeBuilder(out TypeBuilder type); ConstructorBuilder constructor = type.DefineDefaultConstructor(MethodAttributes.Public); ConstructorBuilder constructor2 = type.DefineConstructor(MethodAttributes.Public, CallingConventions.Standard, [typeof(int)]); constructor2.DefineParameter(1, ParameterAttributes.None, "parameter1"); @@ -29,7 +29,7 @@ public void DefineConstructorsTest() il.Emit(OpCodes.Stfld, fieldBuilderA); il.Emit(OpCodes.Ret); type.CreateType(); - saveMethod.Invoke(ab, [file.Path]); + ab.Save(file.Path); using (MetadataLoadContext mlc = new MetadataLoadContext(new CoreMetadataAssemblyResolver())) { @@ -52,7 +52,7 @@ public void DefineConstructorsTest() [Fact] public void DefineDefaultConstructor_WithTypeBuilderParent() { - AssemblyBuilder ab = AssemblySaveTools.PopulateAssemblyBuilderTypeBuilderAndSaveMethod(out TypeBuilder type, out MethodInfo _); + AssemblyBuilder ab = AssemblySaveTools.PopulateAssemblyBuilderAndTypeBuilder(out TypeBuilder type); type.CreateType(); TypeBuilder child = ab.GetDynamicModule("MyModule").DefineType("ChildType", TypeAttributes.Public | TypeAttributes.Class); child.SetParent(type); @@ -70,7 +70,7 @@ public void DefineDefaultConstructor_TypesWithGenericParents() { using (TempFile file = TempFile.Create()) { - AssemblyBuilder ab = AssemblySaveTools.PopulateAssemblyBuilderTypeBuilderAndSaveMethod(out TypeBuilder type, out MethodInfo saveMethod); + AssemblyBuilder ab = AssemblySaveTools.PopulateAssemblyBuilderAndTypeBuilder(out TypeBuilder type); type.DefineGenericParameters("T"); ConstructorBuilder constructor = type.DefineConstructor(MethodAttributes.Public, CallingConventions.Standard, Type.EmptyTypes); FieldBuilder field = type.DefineField("TestField", typeof(bool), FieldAttributes.Public | FieldAttributes.Static); @@ -94,23 +94,26 @@ public void DefineDefaultConstructor_TypesWithGenericParents() type2.SetParent(genericList); type2.DefineDefaultConstructor(MethodAttributes.Public); type2.CreateTypeInfo(); - saveMethod.Invoke(ab, [file.Path]); - - Assembly assemblyFromDisk = AssemblySaveTools.LoadAssemblyFromPath(file.Path); - ConstructorInfo[] ctors = assemblyFromDisk.GetType("MyType").GetConstructors(); - Assert.Equal(1, ctors.Length); - Assert.Empty(ctors[0].GetParameters()); - Type derivedFromFile = assemblyFromDisk.GetType("Derived"); - Assert.NotNull(derivedFromFile.GetConstructor(Type.EmptyTypes)); - Assert.Equal(genericParent.FullName, derivedFromFile.BaseType.FullName); - Assert.NotNull(assemblyFromDisk.GetType("Type2").GetConstructor(Type.EmptyTypes)); + ab.Save(file.Path); + + using (MetadataLoadContext mlc = new MetadataLoadContext(new CoreMetadataAssemblyResolver())) + { + Assembly assemblyFromDisk = mlc.LoadFromAssemblyPath(file.Path); + ConstructorInfo[] ctors = assemblyFromDisk.GetType("MyType").GetConstructors(); + Assert.Equal(1, ctors.Length); + Assert.Empty(ctors[0].GetParameters()); + Type derivedFromFile = assemblyFromDisk.GetType("Derived"); + Assert.NotNull(derivedFromFile.GetConstructor(Type.EmptyTypes)); + Assert.Equal(genericParent.FullName, derivedFromFile.BaseType.FullName); + Assert.NotNull(assemblyFromDisk.GetType("Type2").GetConstructor(Type.EmptyTypes)); + } } } [Fact] public void DefineDefaultConstructor_Interface_ThrowsInvalidOperationException() { - AssemblyBuilder ab = AssemblySaveTools.PopulateAssemblyBuilderAndSaveMethod(new AssemblyName("MyAssembly"), null, typeof(string), out var _); + AssemblyBuilder ab = AssemblySaveTools.PopulateAssemblyBuilder(new AssemblyName("MyAssembly")); TypeBuilder type = ab.DefineDynamicModule("MyModule").DefineType("MyType", TypeAttributes.Public | TypeAttributes.Interface | TypeAttributes.Abstract); Assert.Throws(() => type.DefineDefaultConstructor(MethodAttributes.Public)); } @@ -118,7 +121,7 @@ public void DefineDefaultConstructor_Interface_ThrowsInvalidOperationException() [Fact] public void DefineDefaultConstructor_ThrowsNotSupportedException_IfParentNotCreated() { - AssemblyBuilder ab = AssemblySaveTools.PopulateAssemblyBuilderTypeBuilderAndSaveMethod(out TypeBuilder type, out MethodInfo _); + AssemblyBuilder ab = AssemblySaveTools.PopulateAssemblyBuilderAndTypeBuilder(out TypeBuilder type); TypeBuilder child = ab.GetDynamicModule("MyModule").DefineType("MyType", TypeAttributes.Public); child.SetParent(type); Assert.Throws(() => child.DefineDefaultConstructor(MethodAttributes.Public)); @@ -127,14 +130,14 @@ public void DefineDefaultConstructor_ThrowsNotSupportedException_IfParentNotCrea [Fact] public void DefineDefaultConstructor_StaticVirtual_ThrowsArgumentException() { - AssemblySaveTools.PopulateAssemblyBuilderTypeBuilderAndSaveMethod(out TypeBuilder type, out MethodInfo saveMethod); + AssemblySaveTools.PopulateAssemblyBuilderAndTypeBuilder(out TypeBuilder type); AssertExtensions.Throws(null, () => type.DefineDefaultConstructor(MethodAttributes.Virtual | MethodAttributes.Static)); } [Fact] public void DefineDefaultConstructor_ParentNoDefaultConstructor_ThrowsNotSupportedException() { - AssemblyBuilder ab = AssemblySaveTools.PopulateAssemblyBuilderTypeBuilderAndSaveMethod(out TypeBuilder type, out MethodInfo _); + AssemblyBuilder ab = AssemblySaveTools.PopulateAssemblyBuilderAndTypeBuilder(out TypeBuilder type); FieldBuilder field = type.DefineField("TestField", typeof(int), FieldAttributes.Family); ConstructorBuilder constructor = type.DefineConstructor(MethodAttributes.Public, CallingConventions.HasThis, new[] { typeof(int) }); @@ -157,7 +160,7 @@ public void DefineDefaultConstructor_ParentNoDefaultConstructor_ThrowsNotSupport [InlineData(MethodAttributes.PrivateScope)] public void DefineDefaultConstructor_ParentPrivateDefaultConstructor_ThrowsNotSupportedException(MethodAttributes attributes) { - AssemblySaveTools.PopulateAssemblyBuilderTypeBuilderAndSaveMethod(out TypeBuilder baseType, out MethodInfo _); + AssemblySaveTools.PopulateAssemblyBuilderAndTypeBuilder(out TypeBuilder baseType); ConstructorBuilder constructor = baseType.DefineConstructor(attributes, CallingConventions.HasThis, new[] { typeof(int) }); constructor.GetILGenerator().Emit(OpCodes.Ret); @@ -169,7 +172,7 @@ public void DefineDefaultConstructor_ParentPrivateDefaultConstructor_ThrowsNotSu [Fact] public void GetConstructor_DeclaringTypeOfConstructorGenericTypeDefinition() { - AssemblySaveTools.PopulateAssemblyBuilderTypeBuilderAndSaveMethod(out TypeBuilder type, out MethodInfo _); + AssemblySaveTools.PopulateAssemblyBuilderAndTypeBuilder(out TypeBuilder type); type.DefineGenericParameters("T"); ConstructorBuilder ctor = type.DefineDefaultConstructor(MethodAttributes.PrivateScope | MethodAttributes.Public | MethodAttributes.HideBySig | MethodAttributes.SpecialName); @@ -180,7 +183,7 @@ public void GetConstructor_DeclaringTypeOfConstructorGenericTypeDefinition() [Fact] public void TypeBuilder_GetConstructorWorks() { - AssemblySaveTools.PopulateAssemblyBuilderTypeBuilderAndSaveMethod(out TypeBuilder type, out MethodInfo _); + AssemblySaveTools.PopulateAssemblyBuilderAndTypeBuilder(out TypeBuilder type); type.DefineGenericParameters("T"); ConstructorBuilder ctor = type.DefineDefaultConstructor(MethodAttributes.Public | MethodAttributes.HideBySig | MethodAttributes.RTSpecialName); @@ -194,7 +197,7 @@ public void TypeBuilder_GetConstructorWorks() [Fact] public void GetConstructor_DeclaringTypeOfConstructorNotGenericTypeDefinitionOfType_ThrowsArgumentException() { - AssemblySaveTools.PopulateAssemblyBuilderTypeBuilderAndSaveMethod(out TypeBuilder type1, out MethodInfo _); + AssemblySaveTools.PopulateAssemblyBuilderAndTypeBuilder(out TypeBuilder type1); type1.DefineGenericParameters("T"); TypeBuilder type2 = ((ModuleBuilder)type1.Module).DefineType("TestType2", TypeAttributes.Class | TypeAttributes.Public); @@ -210,7 +213,7 @@ public void GetConstructor_DeclaringTypeOfConstructorNotGenericTypeDefinitionOfT [Fact] public void GetConstructor_TypeNotGeneric_ThrowsArgumentException() { - AssemblySaveTools.PopulateAssemblyBuilderTypeBuilderAndSaveMethod(out TypeBuilder type, out MethodInfo _); + AssemblySaveTools.PopulateAssemblyBuilderAndTypeBuilder(out TypeBuilder type); ConstructorBuilder ctor = type.DefineDefaultConstructor(MethodAttributes.Public); diff --git a/src/libraries/System.Reflection.Emit/tests/PersistableAssemblyBuilder/AssemblySaveCustomAttributeTests.cs b/src/libraries/System.Reflection.Emit/tests/PersistableAssemblyBuilder/AssemblySaveCustomAttributeTests.cs index 7d7191c8c365a0..e2f51e70dab228 100644 --- a/src/libraries/System.Reflection.Emit/tests/PersistableAssemblyBuilder/AssemblySaveCustomAttributeTests.cs +++ b/src/libraries/System.Reflection.Emit/tests/PersistableAssemblyBuilder/AssemblySaveCustomAttributeTests.cs @@ -42,12 +42,15 @@ public void AssemblyModuleWithCustomAttributes() { WriteAssemblyToDisk(assemblyName, Type.EmptyTypes, file.Path, _attributes, _attributes); - Assembly assemblyFromDisk = AssemblySaveTools.LoadAssemblyFromPath(file.Path); - Module moduleFromDisk = assemblyFromDisk.Modules.First(); + using (MetadataLoadContext mlc = new MetadataLoadContext(new CoreMetadataAssemblyResolver())) + { + Assembly assemblyFromDisk = mlc.LoadFromAssemblyPath(file.Path); + Module moduleFromDisk = assemblyFromDisk.Modules.First(); - AssemblySaveTools.AssertAssemblyNameAndModule(assemblyName, assemblyFromDisk.GetName(), moduleFromDisk); - ValidateAttributes(assemblyFromDisk.GetCustomAttributesData()); - ValidateAttributes(moduleFromDisk.GetCustomAttributesData()); + AssemblySaveTools.AssertAssemblyNameAndModule(assemblyName, assemblyFromDisk.GetName(), moduleFromDisk); + ValidateAttributes(assemblyFromDisk.GetCustomAttributesData()); + ValidateAttributes(moduleFromDisk.GetCustomAttributesData()); + } } } @@ -61,33 +64,36 @@ public void MethodFieldWithCustomAttributes() WriteAssemblyToDisk(PopulateAssemblyName(), types, file.Path, typeAttributes: _attributes, methodAttributes: _attributes, fieldAttributes: _attributes); - Assembly assemblyFromDisk = AssemblySaveTools.LoadAssemblyFromPath(file.Path); + using (MetadataLoadContext mlc = new MetadataLoadContext(new CoreMetadataAssemblyResolver())) + { + Assembly assemblyFromDisk = mlc.LoadFromAssemblyPath(file.Path); - Module moduleFromDisk = assemblyFromDisk.Modules.First(); - Type[] typesFromDisk = moduleFromDisk.GetTypes(); + Module moduleFromDisk = assemblyFromDisk.Modules.First(); + Type[] typesFromDisk = moduleFromDisk.GetTypes(); - Assert.Equal(types.Length, typesFromDisk.Length); + Assert.Equal(types.Length, typesFromDisk.Length); - for (int i = 0; i < types.Length; i++) - { - Type typeFromDisk = typesFromDisk[i]; - Type sourceType = types[i]; - MethodInfo[] methodsFromDisk = typeFromDisk.IsValueType ? typeFromDisk.GetMethods(BindingFlags.DeclaredOnly) : typeFromDisk.GetMethods(); - FieldInfo[] fieldsFromDisk = typeFromDisk.GetFields(); + for (int i = 0; i < types.Length; i++) + { + Type typeFromDisk = typesFromDisk[i]; + Type sourceType = types[i]; + MethodInfo[] methodsFromDisk = typeFromDisk.IsValueType ? typeFromDisk.GetMethods(BindingFlags.DeclaredOnly) : typeFromDisk.GetMethods(); + FieldInfo[] fieldsFromDisk = typeFromDisk.GetFields(); - AssemblySaveTools.AssertTypeProperties(sourceType, typeFromDisk); - AssemblySaveTools.AssertMethods(sourceType.IsValueType ? sourceType.GetMethods(BindingFlags.DeclaredOnly) : sourceType.GetMethods(), methodsFromDisk); - AssemblySaveTools.AssertFields(sourceType.GetFields(), fieldsFromDisk); - ValidateAttributes(typeFromDisk.GetCustomAttributesData()); + AssemblySaveTools.AssertTypeProperties(sourceType, typeFromDisk); + AssemblySaveTools.AssertMethods(sourceType.IsValueType ? sourceType.GetMethods(BindingFlags.DeclaredOnly) : sourceType.GetMethods(), methodsFromDisk); + AssemblySaveTools.AssertFields(sourceType.GetFields(), fieldsFromDisk); + ValidateAttributes(typeFromDisk.GetCustomAttributesData()); - for (int j = 0; j < methodsFromDisk.Length; j++) - { - ValidateAttributes(methodsFromDisk[j].GetCustomAttributesData()); - } + for (int j = 0; j < methodsFromDisk.Length; j++) + { + ValidateAttributes(methodsFromDisk[j].GetCustomAttributesData()); + } - for (int j = 0; j < fieldsFromDisk.Length; j++) - { - ValidateAttributes(fieldsFromDisk[j].GetCustomAttributesData()); + for (int j = 0; j < fieldsFromDisk.Length; j++) + { + ValidateAttributes(fieldsFromDisk[j].GetCustomAttributesData()); + } } } } @@ -119,10 +125,10 @@ private static void WriteAssemblyToDisk(AssemblyName assemblyName, Type[] types, List? moduleAttributes = null, List? typeAttributes = null, List? methodAttributes = null, List? fieldAttributes = null) { - AssemblyBuilder assemblyBuilder = AssemblySaveTools.PopulateAssemblyBuilderAndSaveMethod(assemblyName, assemblyAttributes, typeof(string), out MethodInfo saveMethod); + AssemblyBuilder assemblyBuilder = AssemblySaveTools.PopulateAssemblyBuilder(assemblyName, assemblyAttributes); ModuleBuilder mb = assemblyBuilder.DefineDynamicModule(assemblyName.Name); PopulateMembersForModule(mb, types, moduleAttributes, typeAttributes, methodAttributes, fieldAttributes); - saveMethod.Invoke(assemblyBuilder, new object[] { fileLocation }); + assemblyBuilder.Save(fileLocation); } private static void PopulateMembersForModule(ModuleBuilder mb, Type[] types, List? moduleAttributes, @@ -192,62 +198,64 @@ public void CreateStructWithPseudoCustomAttributesTest() new CustomAttributeBuilder(typeof(SpecialNameAttribute).GetConstructor(Type.EmptyTypes), new object[] { }) }; - AssemblyBuilder ab = AssemblySaveTools.PopulateAssemblyBuilderAndSaveMethod( - PopulateAssemblyName(), null, typeof(string), out MethodInfo saveMethod); + AssemblyBuilder ab = AssemblySaveTools.PopulateAssemblyBuilder(PopulateAssemblyName()); TypeBuilder tb = ab.DefineDynamicModule("Module").DefineType(type.FullName, type.Attributes, type.BaseType); DefineFieldsAndSetAttributes(fieldAttributes.ToList(), type.GetFields(), tb); typeAttributes.ForEach(tb.SetCustomAttribute); tb.CreateType(); - saveMethod.Invoke(ab, new object[] { file.Path }); + ab.Save(file.Path); - Assembly assemblyFromDisk = AssemblySaveTools.LoadAssemblyFromPath(file.Path); - Module moduleFromDisk = assemblyFromDisk.Modules.First(); - Type testType = moduleFromDisk.GetTypes()[0]; - IList attributesFromDisk = testType.GetCustomAttributesData(); - - Assert.Equal(typeAttributes.Count - 3, attributesFromDisk.Count); // 3 pseudo attributes - Assert.True((testType.Attributes & TypeAttributes.Serializable) != 0); // SerializableAttribute - Assert.True((testType.Attributes & TypeAttributes.SpecialName) != 0); // SpecialNameAttribute - Assert.True((testType.Attributes & TypeAttributes.ExplicitLayout) != 0); // StructLayoutAttribute - Assert.True((testType.Attributes & TypeAttributes.UnicodeClass) != 0); // StructLayoutAttribute, not sure if we could test the PackingSize and Size - - for (int i = 0; i < attributesFromDisk.Count; i++) + using (MetadataLoadContext mlc = new MetadataLoadContext(new CoreMetadataAssemblyResolver())) { - switch (attributesFromDisk[i].AttributeType.Name) + Assembly assemblyFromDisk = mlc.LoadFromAssemblyPath(file.Path); + Module moduleFromDisk = assemblyFromDisk.Modules.First(); + Type testType = moduleFromDisk.GetTypes()[0]; + IList attributesFromDisk = testType.GetCustomAttributesData(); + + Assert.Equal(typeAttributes.Count - 3, attributesFromDisk.Count); // 3 pseudo attributes + Assert.True((testType.Attributes & TypeAttributes.Serializable) != 0); // SerializableAttribute + Assert.True((testType.Attributes & TypeAttributes.SpecialName) != 0); // SpecialNameAttribute + Assert.True((testType.Attributes & TypeAttributes.ExplicitLayout) != 0); // StructLayoutAttribute + Assert.True((testType.Attributes & TypeAttributes.UnicodeClass) != 0); // StructLayoutAttribute, not sure if we could test the PackingSize and Size + + for (int i = 0; i < attributesFromDisk.Count; i++) { - case "GuidAttribute": - Assert.Equal(s_guidPair.args[0], attributesFromDisk[i].ConstructorArguments[0].Value); - break; - default: - Assert.Fail($"Not expected attribute : {attributesFromDisk[i].AttributeType.Name}"); - break; + switch (attributesFromDisk[i].AttributeType.Name) + { + case "GuidAttribute": + Assert.Equal(s_guidPair.args[0], attributesFromDisk[i].ConstructorArguments[0].Value); + break; + default: + Assert.Fail($"Not expected attribute : {attributesFromDisk[i].AttributeType.Name}"); + break; + } } - } - FieldInfo field = testType.GetFields()[0]; - IList fieldAttributesFromDisk = field.GetCustomAttributesData(); + FieldInfo field = testType.GetFields()[0]; + IList fieldAttributesFromDisk = field.GetCustomAttributesData(); - Assert.Equal(3, fieldAttributesFromDisk.Count); - Assert.True((field.Attributes & FieldAttributes.NotSerialized) != 0); // NonSerializedAttribute - Assert.True((field.Attributes & FieldAttributes.SpecialName) != 0); // SpecialNameAttribute - Assert.True((field.Attributes & FieldAttributes.HasFieldMarshal) != 0); // MarshalAsAttribute + Assert.Equal(3, fieldAttributesFromDisk.Count); + Assert.True((field.Attributes & FieldAttributes.NotSerialized) != 0); // NonSerializedAttribute + Assert.True((field.Attributes & FieldAttributes.SpecialName) != 0); // SpecialNameAttribute + Assert.True((field.Attributes & FieldAttributes.HasFieldMarshal) != 0); // MarshalAsAttribute - for (int i = 0; i < fieldAttributesFromDisk.Count; i++) - { - switch (fieldAttributesFromDisk[i].AttributeType.Name) + for (int i = 0; i < fieldAttributesFromDisk.Count; i++) { - case "FieldOffsetAttribute": - Assert.Equal(2, fieldAttributesFromDisk[i].ConstructorArguments[0].Value); - break; - case "MarshalAsAttribute": - Assert.Equal(UnmanagedType.I4, (UnmanagedType)fieldAttributesFromDisk[i].ConstructorArguments[0].Value); - break; - case "GuidAttribute": - Assert.Equal(s_guidPair.args[0], fieldAttributesFromDisk[i].ConstructorArguments[0].Value); - break; - default: - Assert.Fail($"Not expected attribute : {fieldAttributesFromDisk[i].AttributeType.Name}"); - break; + switch (fieldAttributesFromDisk[i].AttributeType.Name) + { + case "FieldOffsetAttribute": + Assert.Equal(2, fieldAttributesFromDisk[i].ConstructorArguments[0].Value); + break; + case "MarshalAsAttribute": + Assert.Equal(UnmanagedType.I4, (UnmanagedType)fieldAttributesFromDisk[i].ConstructorArguments[0].Value); + break; + case "GuidAttribute": + Assert.Equal(s_guidPair.args[0], fieldAttributesFromDisk[i].ConstructorArguments[0].Value); + break; + default: + Assert.Fail($"Not expected attribute : {fieldAttributesFromDisk[i].AttributeType.Name}"); + break; + } } } } @@ -282,128 +290,131 @@ public void InterfacesWithPseudoCustomAttributes() new CustomAttributeBuilder(marshalAsEnumCtor, new object[] { UnmanagedType.CustomMarshaler }, new FieldInfo[] { typeof(MarshalAsAttribute).GetField("MarshalType")}, new object[] { typeof(EmptyTestClass).AssemblyQualifiedName })}; - AssemblyBuilder ab = AssemblySaveTools.PopulateAssemblyBuilderAndSaveMethod(PopulateAssemblyName(), null, typeof(string), out MethodInfo saveMethod); + AssemblyBuilder ab = AssemblySaveTools.PopulateAssemblyBuilder(PopulateAssemblyName()); TypeBuilder tb = ab.DefineDynamicModule("Module").DefineType(type.FullName, type.Attributes); typeAttributes.ForEach(tb.SetCustomAttribute); DefineMethodsAndSetAttributes(methodAttributes, tb, type.GetMethods(), parameterAttributes); tb.CreateType(); - saveMethod.Invoke(ab, new object[] { file.Path }); + ab.Save(file.Path); - Assembly assemblyFromDisk = AssemblySaveTools.LoadAssemblyFromPath(file.Path); - Type testType = assemblyFromDisk.Modules.First().GetTypes()[0]; - IList attributesFromDisk = testType.GetCustomAttributesData(); - - Assert.Equal(typeAttributes.Count, attributesFromDisk.Count); - Assert.True((testType.Attributes & TypeAttributes.Import) != 0); // ComImportAttribute - Assert.True((testType.Attributes & TypeAttributes.HasSecurity) != 0); // SuppressUnmanagedCodeSecurityAttribute - for (int i = 0; i < attributesFromDisk.Count; i++) - { - switch (attributesFromDisk[i].AttributeType.Name) - { - case "ComImportAttribute": // just making sure that these attributes are expected - case "SuppressUnmanagedCodeSecurityAttribute": - break; - case "GuidAttribute": - Assert.Equal(s_guidPair.args[0], attributesFromDisk[i].ConstructorArguments[0].Value); - break; - default: - Assert.Fail($"Not expected attribute : {attributesFromDisk[i].AttributeType.Name}"); - break; - } - } - - foreach (var method in testType.GetMethods()) + using (MetadataLoadContext mlc = new MetadataLoadContext(new CoreMetadataAssemblyResolver())) { - IList methodAttributesFromDisk = method.GetCustomAttributesData(); - - Assert.True((method.Attributes & MethodAttributes.HasSecurity) != 0); // SuppressUnmanagedCodeSecurityAttribute - Assert.True((method.Attributes & MethodAttributes.SpecialName) != 0); // SpecialNameAttribute - MethodImplAttributes methodImpl = method.GetMethodImplementationFlags(); - Assert.True((methodImpl & MethodImplAttributes.NoInlining) != 0); // MethodImplAttribute - Assert.True((methodImpl & MethodImplAttributes.AggressiveOptimization) != 0); // MethodImplAttribute - Assert.True((methodImpl & MethodImplAttributes.PreserveSig) != 0); // PreserveSigAttribute - Assert.Equal(methodAttributes.Count - 2, methodAttributesFromDisk.Count); - - for (int i = 0; i < methodAttributesFromDisk.Count; i++) + Assembly assemblyFromDisk = mlc.LoadFromAssemblyPath(file.Path); + Type testType = assemblyFromDisk.Modules.First().GetTypes()[0]; + IList attributesFromDisk = testType.GetCustomAttributesData(); + + Assert.Equal(typeAttributes.Count, attributesFromDisk.Count); + Assert.True((testType.Attributes & TypeAttributes.Import) != 0); // ComImportAttribute + Assert.True((testType.Attributes & TypeAttributes.HasSecurity) != 0); // SuppressUnmanagedCodeSecurityAttribute + for (int i = 0; i < attributesFromDisk.Count; i++) { - switch (methodAttributesFromDisk[i].AttributeType.Name) + switch (attributesFromDisk[i].AttributeType.Name) { + case "ComImportAttribute": // just making sure that these attributes are expected case "SuppressUnmanagedCodeSecurityAttribute": - case "PreserveSigAttribute": break; case "GuidAttribute": - Assert.Equal(s_guidPair.args[0], methodAttributesFromDisk[i].ConstructorArguments[0].Value); - break; - case "DllImportAttribute": - { - CustomAttributeData attribute = methodAttributesFromDisk[i]; - Assert.Equal("test.dll", attribute.ConstructorArguments[0].Value); - - for (int j = 0; j < attribute.NamedArguments.Count; j++) - { - switch (attribute.NamedArguments[j].MemberName) - { - case "CharSet": - Assert.Equal(CharSet.Ansi, (CharSet)attribute.NamedArguments[j].TypedValue.Value); - break; - case "SetLastError": - Assert.True((bool)attribute.NamedArguments[j].TypedValue.Value); - break; - case "CallingConvention": - Assert.Equal(CallingConvention.FastCall, (CallingConvention)attribute.NamedArguments[j].TypedValue.Value); - break; - case "BestFitMapping": - Assert.True((bool)attribute.NamedArguments[j].TypedValue.Value); - break; - case "ThrowOnUnmappableChar": - Assert.False((bool)attribute.NamedArguments[j].TypedValue.Value); - break; - } - } - } + Assert.Equal(s_guidPair.args[0], attributesFromDisk[i].ConstructorArguments[0].Value); break; default: - Assert.Fail($"Not expected attribute : {methodAttributesFromDisk[i].AttributeType.Name}"); + Assert.Fail($"Not expected attribute : {attributesFromDisk[i].AttributeType.Name}"); break; } } - foreach(ParameterInfo param in method.GetParameters()) + foreach (var method in testType.GetMethods()) { - IList paramAttributes = param.GetCustomAttributesData(); - - Assert.Equal(5, paramAttributes.Count); - Assert.True((param.Attributes & ParameterAttributes.In) != 0); // InAttribute - Assert.True((param.Attributes & ParameterAttributes.Out) != 0); // OutAttribute - Assert.True((param.Attributes & ParameterAttributes.Optional) != 0); // OptionalAttribute - Assert.True((param.Attributes & ParameterAttributes.HasFieldMarshal) != 0); // MarshalAsAttribute + IList methodAttributesFromDisk = method.GetCustomAttributesData(); - if (param.ParameterType.Equals(typeof(string))) - { - Assert.Equal("Hello", param.DefaultValue); - } + Assert.True((method.Attributes & MethodAttributes.HasSecurity) != 0); // SuppressUnmanagedCodeSecurityAttribute + Assert.True((method.Attributes & MethodAttributes.SpecialName) != 0); // SpecialNameAttribute + MethodImplAttributes methodImpl = method.GetMethodImplementationFlags(); + Assert.True((methodImpl & MethodImplAttributes.NoInlining) != 0); // MethodImplAttribute + Assert.True((methodImpl & MethodImplAttributes.AggressiveOptimization) != 0); // MethodImplAttribute + Assert.True((methodImpl & MethodImplAttributes.PreserveSig) != 0); // PreserveSigAttribute + Assert.Equal(methodAttributes.Count - 2, methodAttributesFromDisk.Count); - for (int i = 0; i < paramAttributes.Count; i++) + for (int i = 0; i < methodAttributesFromDisk.Count; i++) { - switch (paramAttributes[i].AttributeType.Name) + switch (methodAttributesFromDisk[i].AttributeType.Name) { - case "InAttribute": - case "OutAttribute": - case "OptionalAttribute": - break; - case "MarshalAsAttribute": - Assert.Equal(UnmanagedType.CustomMarshaler, (UnmanagedType)paramAttributes[i].ConstructorArguments[0].Value); - Assert.Equal(typeof(EmptyTestClass).AssemblyQualifiedName, - paramAttributes[i].NamedArguments.First(na => na.MemberName == "MarshalType").TypedValue.Value); + case "SuppressUnmanagedCodeSecurityAttribute": + case "PreserveSigAttribute": break; case "GuidAttribute": - Assert.Equal(s_guidPair.args[0], paramAttributes[i].ConstructorArguments[0].Value); + Assert.Equal(s_guidPair.args[0], methodAttributesFromDisk[i].ConstructorArguments[0].Value); + break; + case "DllImportAttribute": + { + CustomAttributeData attribute = methodAttributesFromDisk[i]; + Assert.Equal("test.dll", attribute.ConstructorArguments[0].Value); + + for (int j = 0; j < attribute.NamedArguments.Count; j++) + { + switch (attribute.NamedArguments[j].MemberName) + { + case "CharSet": + Assert.Equal(CharSet.Ansi, (CharSet)attribute.NamedArguments[j].TypedValue.Value); + break; + case "SetLastError": + Assert.True((bool)attribute.NamedArguments[j].TypedValue.Value); + break; + case "CallingConvention": + Assert.Equal(CallingConvention.FastCall, (CallingConvention)attribute.NamedArguments[j].TypedValue.Value); + break; + case "BestFitMapping": + Assert.True((bool)attribute.NamedArguments[j].TypedValue.Value); + break; + case "ThrowOnUnmappableChar": + Assert.False((bool)attribute.NamedArguments[j].TypedValue.Value); + break; + } + } + } break; default: - Assert.Fail($"Not expected attribute : {paramAttributes[i].AttributeType.Name}"); + Assert.Fail($"Not expected attribute : {methodAttributesFromDisk[i].AttributeType.Name}"); break; } } + + foreach (ParameterInfo param in method.GetParameters()) + { + IList paramAttributes = param.GetCustomAttributesData(); + + Assert.Equal(5, paramAttributes.Count); + Assert.True((param.Attributes & ParameterAttributes.In) != 0); // InAttribute + Assert.True((param.Attributes & ParameterAttributes.Out) != 0); // OutAttribute + Assert.True((param.Attributes & ParameterAttributes.Optional) != 0); // OptionalAttribute + Assert.True((param.Attributes & ParameterAttributes.HasFieldMarshal) != 0); // MarshalAsAttribute + + if (param.ParameterType.Equals(typeof(string))) + { + Assert.Equal("Hello", param.DefaultValue); + } + + for (int i = 0; i < paramAttributes.Count; i++) + { + switch (paramAttributes[i].AttributeType.Name) + { + case "InAttribute": + case "OutAttribute": + case "OptionalAttribute": + break; + case "MarshalAsAttribute": + Assert.Equal(UnmanagedType.CustomMarshaler, (UnmanagedType)paramAttributes[i].ConstructorArguments[0].Value); + Assert.Equal(typeof(EmptyTestClass).AssemblyQualifiedName, + paramAttributes[i].NamedArguments.First(na => na.MemberName == "MarshalType").TypedValue.Value); + break; + case "GuidAttribute": + Assert.Equal(s_guidPair.args[0], paramAttributes[i].ConstructorArguments[0].Value); + break; + default: + Assert.Fail($"Not expected attribute : {paramAttributes[i].AttributeType.Name}"); + break; + } + } + } } } } @@ -432,33 +443,35 @@ public void MarshalAsPseudoCustomAttributesTest(CustomAttributeBuilder attribute using (TempFile file = TempFile.Create()) { Type type = typeof(StructWithFields); - AssemblyBuilder ab = AssemblySaveTools.PopulateAssemblyBuilderAndSaveMethod( - PopulateAssemblyName(), null, typeof(string), out MethodInfo saveMethod); + AssemblyBuilder ab = AssemblySaveTools.PopulateAssemblyBuilder(PopulateAssemblyName()); TypeBuilder tb = ab.DefineDynamicModule("Module").DefineType(type.FullName, type.Attributes, type.BaseType); FieldInfo stringField = type.GetFields()[1]; FieldBuilder fb = tb.DefineField(stringField.Name, stringField.FieldType, stringField.Attributes); fb.SetCustomAttribute(attribute); tb.CreateType(); - saveMethod.Invoke(ab, new object[] { file.Path }); + ab.Save(file.Path); - Assembly assemblyFromDisk = AssemblySaveTools.LoadAssemblyFromPath(file.Path); - FieldInfo field = assemblyFromDisk.Modules.First().GetTypes()[0].GetFields()[0]; - CustomAttributeData attributeFromDisk = field.GetCustomAttributesData()[0]; + using (MetadataLoadContext mlc = new MetadataLoadContext(new CoreMetadataAssemblyResolver())) + { + Assembly assemblyFromDisk = mlc.LoadFromAssemblyPath(file.Path); + FieldInfo field = assemblyFromDisk.Modules.First().GetTypes()[0].GetFields()[0]; + CustomAttributeData attributeFromDisk = field.GetCustomAttributesData()[0]; - Assert.Equal(1, field.GetCustomAttributesData().Count); - Assert.True((field.Attributes & FieldAttributes.HasFieldMarshal) != 0); - Assert.Equal(expectedType, (UnmanagedType)attributeFromDisk.ConstructorArguments[0].Value); + Assert.Equal(1, field.GetCustomAttributesData().Count); + Assert.True((field.Attributes & FieldAttributes.HasFieldMarshal) != 0); + Assert.Equal(expectedType, (UnmanagedType)attributeFromDisk.ConstructorArguments[0].Value); - switch (expectedType) - { - case UnmanagedType.CustomMarshaler: - Assert.Equal(typeof(EmptyTestClass).AssemblyQualifiedName, - attributeFromDisk.NamedArguments.First(na => na.MemberName == "MarshalType").TypedValue.Value); - Assert.Equal("MyCookie", attributeFromDisk.NamedArguments.First(na => na.MemberName == "MarshalCookie").TypedValue.Value); - break; - case UnmanagedType.ByValTStr: - Assert.Equal(256, attributeFromDisk.NamedArguments.First(na => na.MemberName == "SizeConst").TypedValue.Value); - break; + switch (expectedType) + { + case UnmanagedType.CustomMarshaler: + Assert.Equal(typeof(EmptyTestClass).AssemblyQualifiedName, + attributeFromDisk.NamedArguments.First(na => na.MemberName == "MarshalType").TypedValue.Value); + Assert.Equal("MyCookie", attributeFromDisk.NamedArguments.First(na => na.MemberName == "MarshalCookie").TypedValue.Value); + break; + case UnmanagedType.ByValTStr: + Assert.Equal(256, attributeFromDisk.NamedArguments.First(na => na.MemberName == "SizeConst").TypedValue.Value); + break; + } } } } @@ -468,40 +481,43 @@ public void EnumBuilderSetCustomAttributesTest() { using (TempFile file = TempFile.Create()) { - AssemblyBuilder ab = AssemblySaveTools.PopulateAssemblyBuilderAndSaveMethod( - PopulateAssemblyName(), null, typeof(string), out MethodInfo saveMethod); + AssemblyBuilder ab = AssemblySaveTools.PopulateAssemblyBuilder(PopulateAssemblyName()); EnumBuilder enumBuilder = ab.DefineDynamicModule("Module").DefineEnum("TestEnum", TypeAttributes.Public, typeof(int)); ConstructorInfo attributeConstructor = typeof(BoolAttribute).GetConstructor(new Type[] { typeof(bool) }); - CustomAttributeBuilder attributeBuilder = new CustomAttributeBuilder(attributeConstructor, new object[] { true }); + CustomAttributeBuilder attributeBuilder = new CustomAttributeBuilder(attributeConstructor, [true]); enumBuilder.SetCustomAttribute(attributeBuilder); enumBuilder.SetCustomAttribute(new CustomAttributeBuilder(s_guidPair.con, s_guidPair.args)); enumBuilder.CreateTypeInfo(); - saveMethod.Invoke(ab, new object[] { file.Path }); + ab.Save(file.Path); - Type testEnum = AssemblySaveTools.LoadAssemblyFromPath(file.Path).Modules.First().GetType("TestEnum"); + using (MetadataLoadContext mlc = new MetadataLoadContext(new CoreMetadataAssemblyResolver())) + { + Type testEnum = mlc.LoadFromAssemblyPath(file.Path).Modules.First().GetType("TestEnum"); - Assert.True(testEnum.IsEnum); - AssemblySaveTools.AssertTypeProperties(enumBuilder, testEnum); + Assert.True(testEnum.IsEnum); + AssemblySaveTools.AssertTypeProperties(enumBuilder, testEnum); - CustomAttributeData[] attributes = testEnum.GetCustomAttributesData().ToArray(); - if (attributes[0].AttributeType.Name == s_guidType.Name) - { - AssertEnumAttributes(s_guidType.FullName, "9ED54F84-A89D-4fcd-A854-44251E925F09", attributes[0]); - AssertEnumAttributes(typeof(BoolAttribute).FullName, true, attributes[1]); - } - else - { - AssertEnumAttributes(s_guidType.FullName, "9ED54F84-A89D-4fcd-A854-44251E925F09", attributes[1]); - AssertEnumAttributes(typeof(BoolAttribute).FullName, true, attributes[0]); - } + CustomAttributeData[] attributes = testEnum.GetCustomAttributesData().ToArray(); + if (attributes[0].AttributeType.Name == s_guidType.Name) + { + AssertEnumAttributes(s_guidType.FullName, "9ED54F84-A89D-4fcd-A854-44251E925F09", attributes[0]); + AssertEnumAttributes(typeof(BoolAttribute).FullName, true, attributes[1]); + } + else + { + AssertEnumAttributes(s_guidType.FullName, "9ED54F84-A89D-4fcd-A854-44251E925F09", attributes[1]); + AssertEnumAttributes(typeof(BoolAttribute).FullName, true, attributes[0]); + } + } } } - private void AssertEnumAttributes(string fullName, object value, CustomAttributeData testAttrbiute) + + private void AssertEnumAttributes(string fullName, object value, CustomAttributeData testAttribute) { - Assert.Equal(fullName, testAttrbiute.AttributeType.FullName); - Assert.Equal(value, testAttrbiute.ConstructorArguments[0].Value); + Assert.Equal(fullName, testAttribute.AttributeType.FullName); + Assert.Equal(value, testAttribute.ConstructorArguments[0].Value); } } diff --git a/src/libraries/System.Reflection.Emit/tests/PersistableAssemblyBuilder/AssemblySaveEnumBuilderTests.cs b/src/libraries/System.Reflection.Emit/tests/PersistableAssemblyBuilder/AssemblySaveEnumBuilderTests.cs index e838af252c31f7..0c40ccafbb1c60 100644 --- a/src/libraries/System.Reflection.Emit/tests/PersistableAssemblyBuilder/AssemblySaveEnumBuilderTests.cs +++ b/src/libraries/System.Reflection.Emit/tests/PersistableAssemblyBuilder/AssemblySaveEnumBuilderTests.cs @@ -64,24 +64,27 @@ public void DefineLiteral(Type underlyingType, object literalValue) { using (TempFile file = TempFile.Create()) { - EnumBuilder enumBuilder = CreateAssemblyAndDefineEnum(out AssemblyBuilder assemblyBuilder, out MethodInfo saveMethod, out TypeBuilder type, underlyingType); + EnumBuilder enumBuilder = CreateAssemblyAndDefineEnum(out AssemblyBuilder assemblyBuilder, out TypeBuilder type, underlyingType); FieldBuilder literal = enumBuilder.DefineLiteral("FieldOne", literalValue); enumBuilder.CreateTypeInfo(); type.CreateTypeInfo(); - saveMethod.Invoke(assemblyBuilder, new object[] { file.Path }); - - Assembly assemblyFromDisk = AssemblySaveTools.LoadAssemblyFromPath(file.Path); - Module moduleFromDisk = assemblyFromDisk.Modules.First(); - Type testEnum = moduleFromDisk.GetType("TestEnum"); - - Assert.True(testEnum.IsEnum); - AssemblySaveTools.AssertTypeProperties(enumBuilder, testEnum); - Assert.Equal(underlyingType.FullName, testEnum.GetEnumUnderlyingType().FullName); - - FieldInfo testField = testEnum.GetField("FieldOne"); - Assert.Equal(enumBuilder.Name, testField.DeclaringType.Name); - Assert.Equal(FieldAttributes.Public | FieldAttributes.Static | FieldAttributes.Literal, literal.Attributes); - Assert.Equal(enumBuilder.AsType().FullName, testField.FieldType.FullName); + assemblyBuilder.Save(file.Path); + + using (MetadataLoadContext mlc = new MetadataLoadContext(new CoreMetadataAssemblyResolver())) + { + Assembly assemblyFromDisk = mlc.LoadFromAssemblyPath(file.Path); + Module moduleFromDisk = assemblyFromDisk.Modules.First(); + Type testEnum = moduleFromDisk.GetType("TestEnum"); + + Assert.True(testEnum.IsEnum); + AssemblySaveTools.AssertTypeProperties(enumBuilder, testEnum); + Assert.Equal(underlyingType.FullName, testEnum.GetEnumUnderlyingType().FullName); + + FieldInfo testField = testEnum.GetField("FieldOne"); + Assert.Equal(enumBuilder.Name, testField.DeclaringType.Name); + Assert.Equal(FieldAttributes.Public | FieldAttributes.Static | FieldAttributes.Literal, literal.Attributes); + Assert.Equal(enumBuilder.AsType().FullName, testField.FieldType.FullName); + } } } @@ -94,7 +97,7 @@ public void SaveArrayTypeSignature(int rank, string name) { using (TempFile file = TempFile.Create()) { - EnumBuilder enumBuilder = CreateAssemblyAndDefineEnum(out AssemblyBuilder ab, out MethodInfo saveMethod, out TypeBuilder tb); + EnumBuilder enumBuilder = CreateAssemblyAndDefineEnum(out AssemblyBuilder ab, out TypeBuilder tb); Type arrayType = rank == 0 ? enumBuilder.MakeArrayType() : enumBuilder.MakeArrayType(rank); MethodBuilder mb = tb.DefineMethod("TestMethod", MethodAttributes.Public); mb.SetReturnType(arrayType); @@ -102,21 +105,23 @@ public void SaveArrayTypeSignature(int rank, string name) mb.GetILGenerator().Emit(OpCodes.Ret); enumBuilder.CreateType(); tb.CreateType(); - saveMethod.Invoke(ab, new object[] { file.Path }); + ab.Save(file.Path); - Type testType = AssemblySaveTools.LoadAssemblyFromPath(file.Path).Modules.First().GetType("TestInterface"); - MethodInfo testMethod = testType.GetMethod("TestMethod"); + using (MetadataLoadContext mlc = new MetadataLoadContext(new CoreMetadataAssemblyResolver())) + { + Type testType = mlc.LoadFromAssemblyPath(file.Path).Modules.First().GetType("TestInterface"); + MethodInfo testMethod = testType.GetMethod("TestMethod"); - AssertArrayTypeSignature(rank, name, testMethod.ReturnType); - AssertArrayTypeSignature(rank, name, testMethod.GetParameters()[1].ParameterType); + AssertArrayTypeSignature(rank, name, testMethod.ReturnType); + AssertArrayTypeSignature(rank, name, testMethod.GetParameters()[1].ParameterType); + } } } private EnumBuilder CreateAssemblyAndDefineEnum(out AssemblyBuilder assemblyBuilder, - out MethodInfo saveMethod, out TypeBuilder type, Type? underlyingType = null) + out TypeBuilder type, Type? underlyingType = null) { - assemblyBuilder = AssemblySaveTools.PopulateAssemblyBuilderAndSaveMethod( - PopulateAssemblyName(), null, typeof(string), out saveMethod); + assemblyBuilder = AssemblySaveTools.PopulateAssemblyBuilder(PopulateAssemblyName()); ModuleBuilder mb = assemblyBuilder.DefineDynamicModule("My Module"); type = mb.DefineType("TestInterface", TypeAttributes.Interface | TypeAttributes.Abstract); return mb.DefineEnum("TestEnum", TypeAttributes.Public, underlyingType == null ? typeof(int) : underlyingType); @@ -135,7 +140,7 @@ public void SaveByRefTypeSignature() { using (TempFile file = TempFile.Create()) { - EnumBuilder eb = CreateAssemblyAndDefineEnum(out AssemblyBuilder assemblyBuilder, out MethodInfo saveMethod, out TypeBuilder tb); + EnumBuilder eb = CreateAssemblyAndDefineEnum(out AssemblyBuilder assemblyBuilder, out TypeBuilder tb); Type byrefType = eb.MakeByRefType(); MethodBuilder mb = tb.DefineMethod("TestMethod", MethodAttributes.Public); mb.SetReturnType(byrefType); @@ -143,14 +148,17 @@ public void SaveByRefTypeSignature() mb.GetILGenerator().Emit(OpCodes.Ret); eb.CreateType(); tb.CreateType(); - saveMethod.Invoke(assemblyBuilder, new object[] { file.Path }); + assemblyBuilder.Save(file.Path); - Type testType = AssemblySaveTools.LoadAssemblyFromPath(file.Path).Modules.First().GetType("TestInterface"); - MethodInfo testMethod = testType.GetMethod("TestMethod"); + using (MetadataLoadContext mlc = new MetadataLoadContext(new CoreMetadataAssemblyResolver())) + { + Type testType = mlc.LoadFromAssemblyPath(file.Path).Modules.First().GetType("TestInterface"); + MethodInfo testMethod = testType.GetMethod("TestMethod"); - Assert.False(testMethod.GetParameters()[0].ParameterType.IsByRef); - AssertByRefType(testMethod.GetParameters()[1].ParameterType); - AssertByRefType(testMethod.ReturnType); + Assert.False(testMethod.GetParameters()[0].ParameterType.IsByRef); + AssertByRefType(testMethod.GetParameters()[1].ParameterType); + AssertByRefType(testMethod.ReturnType); + } } } @@ -165,7 +173,7 @@ public void SavePointerTypeSignature() { using (TempFile file = TempFile.Create()) { - EnumBuilder eb = CreateAssemblyAndDefineEnum(out AssemblyBuilder assemblyBuilder, out MethodInfo saveMethod, out TypeBuilder tb); + EnumBuilder eb = CreateAssemblyAndDefineEnum(out AssemblyBuilder assemblyBuilder, out TypeBuilder tb); Type pointerType = eb.MakePointerType(); MethodBuilder mb = tb.DefineMethod("TestMethod", MethodAttributes.Public); mb.SetReturnType(pointerType); @@ -173,14 +181,17 @@ public void SavePointerTypeSignature() mb.GetILGenerator().Emit(OpCodes.Ret); eb.CreateType(); tb.CreateType(); - saveMethod.Invoke(assemblyBuilder, new object[] { file.Path }); + assemblyBuilder.Save(file.Path); - Type testType = AssemblySaveTools.LoadAssemblyFromPath(file.Path).Modules.First().GetType("TestInterface"); - MethodInfo testMethod = testType.GetMethod("TestMethod"); + using (MetadataLoadContext mlc = new MetadataLoadContext(new CoreMetadataAssemblyResolver())) + { + Type testType = mlc.LoadFromAssemblyPath(file.Path).Modules.First().GetType("TestInterface"); + MethodInfo testMethod = testType.GetMethod("TestMethod"); - Assert.False(testMethod.GetParameters()[0].ParameterType.IsPointer); - AssertPointerType(testMethod.GetParameters()[1].ParameterType); - AssertPointerType(testMethod.ReturnType); + Assert.False(testMethod.GetParameters()[0].ParameterType.IsPointer); + AssertPointerType(testMethod.GetParameters()[1].ParameterType); + AssertPointerType(testMethod.ReturnType); + } } } diff --git a/src/libraries/System.Reflection.Emit/tests/PersistableAssemblyBuilder/AssemblySaveEventBuilderTests.cs b/src/libraries/System.Reflection.Emit/tests/PersistableAssemblyBuilder/AssemblySaveEventBuilderTests.cs index 0d95824b45d9ff..d7c03fa49fc2b2 100644 --- a/src/libraries/System.Reflection.Emit/tests/PersistableAssemblyBuilder/AssemblySaveEventBuilderTests.cs +++ b/src/libraries/System.Reflection.Emit/tests/PersistableAssemblyBuilder/AssemblySaveEventBuilderTests.cs @@ -16,7 +16,7 @@ public void DefineEventAndItsAccessors() { using (TempFile file = TempFile.Create()) { - AssemblyBuilder ab = AssemblySaveTools.PopulateAssemblyBuilderTypeBuilderAndSaveMethod(out TypeBuilder type, out MethodInfo saveMethod); + AssemblyBuilder ab = AssemblySaveTools.PopulateAssemblyBuilderAndTypeBuilder(out TypeBuilder type); EventBuilder eventType = type.DefineEvent("TestEvent", EventAttributes.SpecialName, typeof(int)); MethodBuilder addMethod = type.DefineMethod("AddMethod", MethodAttributes.Public | MethodAttributes.SpecialName); MethodBuilder addMethod2 = type.DefineMethod("AddMethod2", MethodAttributes.Public | MethodAttributes.HideBySig, typeof(int), Type.EmptyTypes); @@ -42,29 +42,32 @@ public void DefineEventAndItsAccessors() otherILGenerator.Emit(OpCodes.Ret); eventType.AddOtherMethod(otherMethod); type.CreateType(); - saveMethod.Invoke(ab, new[] { file.Path }); + ab.Save(file.Path); - Assembly assemblyFromDisk = AssemblySaveTools.LoadAssemblyFromPath(file.Path); - Type typeFromDisk = assemblyFromDisk.Modules.First().GetType("MyType"); - EventInfo eventFromDisk = typeFromDisk.GetEvent("TestEvent"); - Assert.Equal(addMethod2.Name, eventFromDisk.AddMethod.Name); - Assert.Equal(raiseMethod.Name, eventFromDisk.RaiseMethod.Name); - Assert.Equal(removeMethod.Name, eventFromDisk.RemoveMethod.Name); - Assert.Equal(typeof(int).FullName, eventFromDisk.EventHandlerType.FullName); - Assert.NotNull(typeFromDisk.GetMethod("OtherMethod", BindingFlags.NonPublic | BindingFlags.Instance)); - Assert.Equal(EventAttributes.SpecialName, eventFromDisk.Attributes); - IList caData = eventFromDisk.GetCustomAttributesData(); - Assert.Equal(1, caData.Count); - Assert.Equal(typeof(IntPropertyAttribute).FullName, caData[0].AttributeType.FullName); - Assert.Equal(1, caData[0].ConstructorArguments.Count); - Assert.Equal(9, caData[0].ConstructorArguments[0].Value); + using (MetadataLoadContext mlc = new MetadataLoadContext(new CoreMetadataAssemblyResolver())) + { + Assembly assemblyFromDisk = mlc.LoadFromAssemblyPath(file.Path); + Type typeFromDisk = assemblyFromDisk.Modules.First().GetType("MyType"); + EventInfo eventFromDisk = typeFromDisk.GetEvent("TestEvent"); + Assert.Equal(addMethod2.Name, eventFromDisk.AddMethod.Name); + Assert.Equal(raiseMethod.Name, eventFromDisk.RaiseMethod.Name); + Assert.Equal(removeMethod.Name, eventFromDisk.RemoveMethod.Name); + Assert.Equal(typeof(int).FullName, eventFromDisk.EventHandlerType.FullName); + Assert.NotNull(typeFromDisk.GetMethod("OtherMethod", BindingFlags.NonPublic | BindingFlags.Instance)); + Assert.Equal(EventAttributes.SpecialName, eventFromDisk.Attributes); + IList caData = eventFromDisk.GetCustomAttributesData(); + Assert.Equal(1, caData.Count); + Assert.Equal(typeof(IntPropertyAttribute).FullName, caData[0].AttributeType.FullName); + Assert.Equal(1, caData[0].ConstructorArguments.Count); + Assert.Equal(9, caData[0].ConstructorArguments[0].Value); + } } } [Fact] public void Set_NullValue_ThrowsArgumentNullException() { - AssemblySaveTools.PopulateAssemblyBuilderTypeBuilderAndSaveMethod(out TypeBuilder type, out MethodInfo _); + AssemblySaveTools.PopulateAssemblyBuilderAndTypeBuilder(out TypeBuilder type); EventBuilder eventBuilder = type.DefineEvent("TestEvent", EventAttributes.None, typeof(string)); AssertExtensions.Throws("eventtype", () => type.DefineEvent("EventTypeNull", EventAttributes.None, null)); @@ -78,7 +81,7 @@ public void Set_NullValue_ThrowsArgumentNullException() [Fact] public void Set_WhenTypeAlreadyCreated_ThrowsInvalidOperationException() { - AssemblySaveTools.PopulateAssemblyBuilderTypeBuilderAndSaveMethod(out TypeBuilder type, out MethodInfo _); + AssemblySaveTools.PopulateAssemblyBuilderAndTypeBuilder(out TypeBuilder type); EventBuilder eventBuilder = type.DefineEvent("TestEvent", EventAttributes.None, typeof(int)); MethodBuilder method = type.DefineMethod("TestMethod", MethodAttributes.Public | MethodAttributes.SpecialName, typeof(int), null); diff --git a/src/libraries/System.Reflection.Emit/tests/PersistableAssemblyBuilder/AssemblySaveILGeneratorTests.cs b/src/libraries/System.Reflection.Emit/tests/PersistableAssemblyBuilder/AssemblySaveILGeneratorTests.cs index f11c899eb30406..b6a24dca28399b 100644 --- a/src/libraries/System.Reflection.Emit/tests/PersistableAssemblyBuilder/AssemblySaveILGeneratorTests.cs +++ b/src/libraries/System.Reflection.Emit/tests/PersistableAssemblyBuilder/AssemblySaveILGeneratorTests.cs @@ -18,23 +18,25 @@ public void MethodWithEmptyBody() { using (TempFile file = TempFile.Create()) { - AssemblyBuilder ab = AssemblySaveTools.PopulateAssemblyBuilderTypeBuilderAndSaveMethod(out TypeBuilder type, out MethodInfo saveMethod); - MethodBuilder methodBuilder = type.DefineMethod("EmptyMethod", MethodAttributes.Public, typeof(void), new[] { typeof(Version) }); + AssemblyBuilder ab = AssemblySaveTools.PopulateAssemblyBuilderAndTypeBuilder(out TypeBuilder type); + MethodBuilder methodBuilder = type.DefineMethod("EmptyMethod", MethodAttributes.Public, typeof(void), [typeof(Version)]); ILGenerator il = methodBuilder.GetILGenerator(); il.Emit(OpCodes.Ret); type.CreateType(); - saveMethod.Invoke(ab, new object[] { file.Path }); - - Assembly assemblyFromDisk = AssemblySaveTools.LoadAssemblyFromPath(file.Path); - Type typeFromDisk = assemblyFromDisk.Modules.First().GetType("MyType"); - MethodInfo method = typeFromDisk.GetMethod("EmptyMethod"); - MethodBody body = method.GetMethodBody(); - Assert.Empty(body.LocalVariables); - Assert.Empty(body.ExceptionHandlingClauses); - byte[]? bodyBytes = body.GetILAsByteArray(); - Assert.NotNull(bodyBytes); - Assert.Equal(OpCodes.Ret.Value, bodyBytes[0]); + ab.Save(file.Path); + using (MetadataLoadContext mlc = new MetadataLoadContext(new CoreMetadataAssemblyResolver())) + { + Assembly assemblyFromDisk = mlc.LoadFromAssemblyPath(file.Path); + Type typeFromDisk = assemblyFromDisk.Modules.First().GetType("MyType"); + MethodInfo method = typeFromDisk.GetMethod("EmptyMethod"); + MethodBody body = method.GetMethodBody(); + Assert.Empty(body.LocalVariables); + Assert.Empty(body.ExceptionHandlingClauses); + byte[]? bodyBytes = body.GetILAsByteArray(); + Assert.NotNull(bodyBytes); + Assert.Equal(OpCodes.Ret.Value, bodyBytes[0]); + } } } @@ -45,7 +47,7 @@ public void MethodReturning_Int(int size) { using (TempFile file = TempFile.Create()) { - AssemblyBuilder ab = AssemblySaveTools.PopulateAssemblyBuilderTypeBuilderAndSaveMethod(out TypeBuilder type, out MethodInfo saveMethod); + AssemblyBuilder ab = AssemblySaveTools.PopulateAssemblyBuilderAndTypeBuilder(out TypeBuilder type); MethodBuilder method = type.DefineMethod("TestMethod", MethodAttributes.Public | MethodAttributes.Static, typeof(int), Type.EmptyTypes); ILGenerator ilGenerator = method.GetILGenerator(size); @@ -53,16 +55,19 @@ public void MethodReturning_Int(int size) ilGenerator.Emit(OpCodes.Ldc_I4, expectedReturn); ilGenerator.Emit(OpCodes.Ret); type.CreateType(); - saveMethod.Invoke(ab, new object[] { file.Path }); - - Assembly assemblyFromDisk = AssemblySaveTools.LoadAssemblyFromPath(file.Path); - Type typeFromDisk = assemblyFromDisk.Modules.First().GetType("MyType"); - MethodInfo methodFromFile = typeFromDisk.GetMethod("TestMethod"); - MethodBody body = methodFromFile.GetMethodBody(); - byte[]? bodyBytes = body.GetILAsByteArray(); - Assert.NotNull(bodyBytes); - Assert.Equal(OpCodes.Ldc_I4_5.Value, bodyBytes[0]); - Assert.Equal(OpCodes.Ret.Value, bodyBytes[1]); + ab.Save(file.Path); + + using (MetadataLoadContext mlc = new MetadataLoadContext(new CoreMetadataAssemblyResolver())) + { + Assembly assemblyFromDisk = mlc.LoadFromAssemblyPath(file.Path); + Type typeFromDisk = assemblyFromDisk.Modules.First().GetType("MyType"); + MethodInfo methodFromFile = typeFromDisk.GetMethod("TestMethod"); + MethodBody body = methodFromFile.GetMethodBody(); + byte[]? bodyBytes = body.GetILAsByteArray(); + Assert.NotNull(bodyBytes); + Assert.Equal(OpCodes.Ldc_I4_5.Value, bodyBytes[0]); + Assert.Equal(OpCodes.Ret.Value, bodyBytes[1]); + } } } @@ -73,10 +78,10 @@ public void TypeWithTwoMethod_ReferenceMethodArguments(int multiplier) { using (TempFile file = TempFile.Create()) { - AssemblyBuilder ab = AssemblySaveTools.PopulateAssemblyBuilderTypeBuilderAndSaveMethod(out TypeBuilder type, out MethodInfo saveMethod); - MethodBuilder multiplyMethod = type.DefineMethod("MultiplyMethod", MethodAttributes.Public | MethodAttributes.Static, typeof(int), new Type[] { typeof(int) }); + AssemblyBuilder ab = AssemblySaveTools.PopulateAssemblyBuilderAndTypeBuilder(out TypeBuilder type); + MethodBuilder multiplyMethod = type.DefineMethod("MultiplyMethod", MethodAttributes.Public | MethodAttributes.Static, typeof(int), [typeof(int)]); multiplyMethod.DefineParameter(1, ParameterAttributes.None, "myParam"); - MethodBuilder addMethod = type.DefineMethod("AddMethod", MethodAttributes.Public | MethodAttributes.Static, typeof(int), new Type[] { typeof(int), typeof(int) }); + MethodBuilder addMethod = type.DefineMethod("AddMethod", MethodAttributes.Public | MethodAttributes.Static, typeof(int), [typeof(int), typeof(int)]); addMethod.DefineParameter(1, ParameterAttributes.None, "firsParam"); addMethod.DefineParameter(2, ParameterAttributes.None, "secondParam"); @@ -92,22 +97,25 @@ public void TypeWithTwoMethod_ReferenceMethodArguments(int multiplier) addMethodIL.Emit(OpCodes.Add); addMethodIL.Emit(OpCodes.Ret); type.CreateType(); - saveMethod.Invoke(ab, new object[] { file.Path }); - - Assembly assemblyFromDisk = AssemblySaveTools.LoadAssemblyFromPath(file.Path); - Type typeFromDisk = assemblyFromDisk.Modules.First().GetType("MyType"); - byte[]? multiplyBody = typeFromDisk.GetMethod("MultiplyMethod").GetMethodBody().GetILAsByteArray(); - byte[]? addBody = typeFromDisk.GetMethod("AddMethod").GetMethodBody().GetILAsByteArray(); - - Assert.NotNull(multiplyBody); - Assert.Equal(OpCodes.Ldarg_0.Value, multiplyBody[0]); - Assert.Equal(OpCodes.Ldc_I4_S.Value, multiplyBody[1]); - Assert.Equal(multiplier, multiplyBody[2]); - Assert.Equal(OpCodes.Mul.Value, multiplyBody[3]); - Assert.NotNull(addBody); - Assert.Equal(OpCodes.Ldarg_0.Value, addBody[0]); - Assert.Equal(OpCodes.Ldarg_1.Value, addBody[1]); - Assert.Equal(OpCodes.Add.Value, addBody[2]); + ab.Save(file.Path); + + using (MetadataLoadContext mlc = new MetadataLoadContext(new CoreMetadataAssemblyResolver())) + { + Assembly assemblyFromDisk = mlc.LoadFromAssemblyPath(file.Path); + Type typeFromDisk = assemblyFromDisk.Modules.First().GetType("MyType"); + byte[]? multiplyBody = typeFromDisk.GetMethod("MultiplyMethod").GetMethodBody().GetILAsByteArray(); + byte[]? addBody = typeFromDisk.GetMethod("AddMethod").GetMethodBody().GetILAsByteArray(); + + Assert.NotNull(multiplyBody); + Assert.Equal(OpCodes.Ldarg_0.Value, multiplyBody[0]); + Assert.Equal(OpCodes.Ldc_I4_S.Value, multiplyBody[1]); + Assert.Equal(multiplier, multiplyBody[2]); + Assert.Equal(OpCodes.Mul.Value, multiplyBody[3]); + Assert.NotNull(addBody); + Assert.Equal(OpCodes.Ldarg_0.Value, addBody[0]); + Assert.Equal(OpCodes.Ldarg_1.Value, addBody[1]); + Assert.Equal(OpCodes.Add.Value, addBody[2]); + } } } @@ -116,9 +124,9 @@ public void MultipleTypesWithMultipleMethods() { using (TempFile file = TempFile.Create()) { - AssemblyBuilder ab = AssemblySaveTools.PopulateAssemblyBuilderTypeBuilderAndSaveMethod(out TypeBuilder type, out MethodInfo saveMethod); - MethodBuilder multiplyMethod = type.DefineMethod("MultiplyMethod", MethodAttributes.Public, typeof(short), new Type[] { typeof(short) }); - MethodBuilder addMethod = type.DefineMethod("AddMethod", MethodAttributes.Public | MethodAttributes.Static, typeof(double), new Type[] { typeof(double) }); + AssemblyBuilder ab = AssemblySaveTools.PopulateAssemblyBuilderAndTypeBuilder(out TypeBuilder type); + MethodBuilder multiplyMethod = type.DefineMethod("MultiplyMethod", MethodAttributes.Public, typeof(short), [typeof(short)]); + MethodBuilder addMethod = type.DefineMethod("AddMethod", MethodAttributes.Public | MethodAttributes.Static, typeof(double), [typeof(double)]); ILGenerator multiplyMethodIL = multiplyMethod.GetILGenerator(); multiplyMethodIL.Emit(OpCodes.Ldarg, 1); @@ -146,38 +154,41 @@ public void MultipleTypesWithMultipleMethods() longMethodIL.Emit(OpCodes.Ldc_I8, (long)1234567); longMethodIL.Emit(OpCodes.Ret); anotherType.CreateType(); - saveMethod.Invoke(ab, new object[] { file.Path }); - - Assembly assemblyFromDisk = AssemblySaveTools.LoadAssemblyFromPath(file.Path); - Module moduleFromFile = assemblyFromDisk.Modules.First(); - Type typeFromDisk = moduleFromFile.GetType("MyType"); - Type anotherTypeFromDisk = moduleFromFile.GetType("AnotherType"); - byte[]? multiplyBody = typeFromDisk.GetMethod("MultiplyMethod").GetMethodBody().GetILAsByteArray(); - byte[]? addBody = typeFromDisk.GetMethod("AddMethod").GetMethodBody().GetILAsByteArray(); - byte[]? stringBody = anotherTypeFromDisk.GetMethod("StringMethod", BindingFlags.NonPublic | BindingFlags.Instance).GetMethodBody().GetILAsByteArray(); - byte[]? floatBody = anotherTypeFromDisk.GetMethod("FloatMethod", BindingFlags.NonPublic | BindingFlags.Instance).GetMethodBody().GetILAsByteArray(); - byte[]? longBody = anotherTypeFromDisk.GetMethod("LongMethod", BindingFlags.NonPublic | BindingFlags.Static).GetMethodBody().GetILAsByteArray(); - - Assert.NotNull(multiplyBody); - Assert.Equal(OpCodes.Ldarg_1.Value, multiplyBody[0]); - Assert.Equal(OpCodes.Ldc_I4_S.Value, multiplyBody[1]); - Assert.Equal(11, multiplyBody[2]); - Assert.NotNull(addBody); - Assert.Equal(OpCodes.Ldarg_0.Value, addBody[0]); - Assert.Equal(OpCodes.Ldc_R8.Value, addBody[1]); - Assert.NotNull(stringBody); - Assert.Equal(OpCodes.Ldstr.Value, stringBody[0]); - Assert.NotNull(floatBody); - Assert.Equal(OpCodes.Ldc_R4.Value, floatBody[0]); - Assert.NotNull(longBody); - Assert.Equal(OpCodes.Ldc_I8.Value, longBody[0]); + ab.Save(file.Path); + + using (MetadataLoadContext mlc = new MetadataLoadContext(new CoreMetadataAssemblyResolver())) + { + Assembly assemblyFromDisk = mlc.LoadFromAssemblyPath(file.Path); + Module moduleFromFile = assemblyFromDisk.Modules.First(); + Type typeFromDisk = moduleFromFile.GetType("MyType"); + Type anotherTypeFromDisk = moduleFromFile.GetType("AnotherType"); + byte[]? multiplyBody = typeFromDisk.GetMethod("MultiplyMethod").GetMethodBody().GetILAsByteArray(); + byte[]? addBody = typeFromDisk.GetMethod("AddMethod").GetMethodBody().GetILAsByteArray(); + byte[]? stringBody = anotherTypeFromDisk.GetMethod("StringMethod", BindingFlags.NonPublic | BindingFlags.Instance).GetMethodBody().GetILAsByteArray(); + byte[]? floatBody = anotherTypeFromDisk.GetMethod("FloatMethod", BindingFlags.NonPublic | BindingFlags.Instance).GetMethodBody().GetILAsByteArray(); + byte[]? longBody = anotherTypeFromDisk.GetMethod("LongMethod", BindingFlags.NonPublic | BindingFlags.Static).GetMethodBody().GetILAsByteArray(); + + Assert.NotNull(multiplyBody); + Assert.Equal(OpCodes.Ldarg_1.Value, multiplyBody[0]); + Assert.Equal(OpCodes.Ldc_I4_S.Value, multiplyBody[1]); + Assert.Equal(11, multiplyBody[2]); + Assert.NotNull(addBody); + Assert.Equal(OpCodes.Ldarg_0.Value, addBody[0]); + Assert.Equal(OpCodes.Ldc_R8.Value, addBody[1]); + Assert.NotNull(stringBody); + Assert.Equal(OpCodes.Ldstr.Value, stringBody[0]); + Assert.NotNull(floatBody); + Assert.Equal(OpCodes.Ldc_R4.Value, floatBody[0]); + Assert.NotNull(longBody); + Assert.Equal(OpCodes.Ldc_I8.Value, longBody[0]); + } } } [Fact] public void ILOffset_Test() { - AssemblyBuilder ab = AssemblySaveTools.PopulateAssemblyBuilderTypeBuilderAndSaveMethod(out TypeBuilder type, out MethodInfo saveMethod); + AssemblyBuilder ab = AssemblySaveTools.PopulateAssemblyBuilderAndTypeBuilder(out TypeBuilder type); MethodBuilder method = type.DefineMethod("Method1", MethodAttributes.Public | MethodAttributes.Static, typeof(Type), Type.EmptyTypes); ILGenerator ilGenerator = method.GetILGenerator(); @@ -191,8 +202,8 @@ public void ILMaxStack_Test() { using (TempFile file = TempFile.Create()) { - AssemblyBuilder ab = AssemblySaveTools.PopulateAssemblyBuilderTypeBuilderAndSaveMethod(out TypeBuilder type, out MethodInfo saveMethod); - MethodBuilder method1 = type.DefineMethod("Method1", MethodAttributes.Public, typeof(long), new [] { typeof(int), typeof(long), typeof(short), typeof(byte) }); + AssemblyBuilder ab = AssemblySaveTools.PopulateAssemblyBuilderAndTypeBuilder(out TypeBuilder type); + MethodBuilder method1 = type.DefineMethod("Method1", MethodAttributes.Public, typeof(long), [typeof(int), typeof(long), typeof(short), typeof(byte)]); ILGenerator il1 = method1.GetILGenerator(); // public int Method1(int x, int y, short z, byte r) => @@ -218,7 +229,7 @@ public void ILMaxStack_Test() il1.Emit(OpCodes.Add); // pop 2 push 1 stack size 1 il1.Emit(OpCodes.Ret); // pop 1 stack size 0 - MethodBuilder method2 = type.DefineMethod("Method2", MethodAttributes.Public, typeof(int), new Type[] { typeof(int), typeof(byte) }); + MethodBuilder method2 = type.DefineMethod("Method2", MethodAttributes.Public, typeof(int), [typeof(int), typeof(byte)]); ILGenerator il2 = method2.GetILGenerator(); // int Method2(int x, int y) => x + (y + 18); @@ -229,18 +240,21 @@ public void ILMaxStack_Test() il2.Emit(OpCodes.Add); // pop 2 push 1 stack size 1 il2.Emit(OpCodes.Ret); // pop 1 stack size 0 type.CreateType(); - saveMethod.Invoke(ab, new object[] { file.Path }); + ab.Save(file.Path); MethodInfo getMaxStackMethod = GetMaxStackMethod(); Assert.Equal(9, getMaxStackMethod.Invoke(il1, null)); Assert.Equal(3, getMaxStackMethod.Invoke(il2, null)); - Assembly assemblyFromDisk = AssemblySaveTools.LoadAssemblyFromPath(file.Path); - Type typeFromDisk = assemblyFromDisk.Modules.First().GetType("MyType"); - MethodBody body1 = typeFromDisk.GetMethod("Method1").GetMethodBody(); - MethodBody body2 = typeFromDisk.GetMethod("Method2").GetMethodBody(); - Assert.Equal(9, body1.MaxStackSize); - Assert.Equal(8, body2.MaxStackSize); // apparently doesn't write lower than 8 + using (MetadataLoadContext mlc = new MetadataLoadContext(new CoreMetadataAssemblyResolver())) + { + Assembly assemblyFromDisk = mlc.LoadFromAssemblyPath(file.Path); + Type typeFromDisk = assemblyFromDisk.Modules.First().GetType("MyType"); + MethodBody body1 = typeFromDisk.GetMethod("Method1").GetMethodBody(); + MethodBody body2 = typeFromDisk.GetMethod("Method2").GetMethodBody(); + Assert.Equal(9, body1.MaxStackSize); + Assert.Equal(8, body2.MaxStackSize); // apparently doesn't write lower than 8 + } } } @@ -262,8 +276,8 @@ public void Label_ConditionalBranching() { using (TempFile file = TempFile.Create()) { - AssemblyBuilder ab = AssemblySaveTools.PopulateAssemblyBuilderTypeBuilderAndSaveMethod(out TypeBuilder type, out MethodInfo saveMethod); - MethodBuilder methodBuilder = type.DefineMethod("Method1", MethodAttributes.Public, typeof(int), new[] { typeof(int), typeof(int) }); + AssemblyBuilder ab = AssemblySaveTools.PopulateAssemblyBuilderAndTypeBuilder(out TypeBuilder type); + MethodBuilder methodBuilder = type.DefineMethod("Method1", MethodAttributes.Public, typeof(int), [typeof(int), typeof(int)]); ILGenerator il = methodBuilder.GetILGenerator(); Label failed = il.DefineLabel(); Label endOfMethod = il.DefineLabel(); @@ -287,24 +301,27 @@ public void Label_ConditionalBranching() il.MarkLabel(endOfMethod); il.Emit(OpCodes.Ret); type.CreateType(); - saveMethod.Invoke(ab, new object[] { file.Path }); + ab.Save(file.Path); MethodInfo getMaxStackMethod = GetMaxStackMethod(); Assert.Equal(2, getMaxStackMethod.Invoke(il, null)); - Assembly assemblyFromDisk = AssemblySaveTools.LoadAssemblyFromPath(file.Path); - Type typeFromDisk = assemblyFromDisk.Modules.First().GetType("MyType"); - byte[]? bodyBytes = typeFromDisk.GetMethod("Method1").GetMethodBody().GetILAsByteArray(); - Assert.Equal( - [ - (byte)OpCodes.Ldarg_1.Value, (byte)OpCodes.Ldc_I4_S.Value, 100, 0, 0, 0, + using (MetadataLoadContext mlc = new MetadataLoadContext(new CoreMetadataAssemblyResolver())) + { + Assembly assemblyFromDisk = mlc.LoadFromAssemblyPath(file.Path); + Type typeFromDisk = assemblyFromDisk.Modules.First().GetType("MyType"); + byte[]? bodyBytes = typeFromDisk.GetMethod("Method1").GetMethodBody().GetILAsByteArray(); + Assert.Equal( + [ + (byte)OpCodes.Ldarg_1.Value, (byte)OpCodes.Ldc_I4_S.Value, 100, 0, 0, 0, (byte)OpCodes.Bgt_S.Value, 13, (byte)OpCodes.Ldarg_2.Value, (byte)OpCodes.Ldc_I4_S.Value, 100, 0, 0, 0, (byte)OpCodes.Bgt_S.Value, 5, (byte)OpCodes.Ldarg_1.Value, (byte)OpCodes.Ldarg_2.Value, (byte)OpCodes.Add.Value, (byte)OpCodes.Br_S.Value, (byte)OpCodes.Break.Value, (byte)OpCodes.Ldc_I4_M1.Value, (byte)OpCodes.Ret.Value - ], bodyBytes); + ], bodyBytes); + } } } @@ -313,8 +330,8 @@ public void Label_SwitchCase() { using (TempFile file = TempFile.Create()) { - AssemblyBuilder ab = AssemblySaveTools.PopulateAssemblyBuilderTypeBuilderAndSaveMethod(out TypeBuilder type, out MethodInfo saveMethod); - MethodBuilder methodBuilder = type.DefineMethod("Method1", MethodAttributes.Public, typeof(string), new[] { typeof(int) }); + AssemblyBuilder ab = AssemblySaveTools.PopulateAssemblyBuilderAndTypeBuilder(out TypeBuilder type); + MethodBuilder methodBuilder = type.DefineMethod("Method1", MethodAttributes.Public, typeof(string), [typeof(int)]); ILGenerator il = methodBuilder.GetILGenerator(); Label defaultCase = il.DefineLabel(); Label endOfMethod = il.DefineLabel(); @@ -358,18 +375,21 @@ public void Label_SwitchCase() il.MarkLabel(endOfMethod); il.Emit(OpCodes.Ret); type.CreateType(); - saveMethod.Invoke(ab, new object[] { file.Path }); + ab.Save(file.Path); MethodInfo getMaxStackMethod = GetMaxStackMethod(); Assert.Equal(1, getMaxStackMethod.Invoke(il, null)); - Assembly assemblyFromDisk = AssemblySaveTools.LoadAssemblyFromPath(file.Path); - Type typeFromDisk = assemblyFromDisk.Modules.First().GetType("MyType"); - byte[]? bodyBytes = typeFromDisk.GetMethod("Method1").GetMethodBody().GetILAsByteArray(); - Assert.Equal((byte)OpCodes.Ldarg_1.Value, bodyBytes[0]); - Assert.Equal((byte)OpCodes.Switch.Value, bodyBytes[1]); - Assert.Equal(5, bodyBytes[2]); // case count - Assert.Equal(69, bodyBytes.Length); + using (MetadataLoadContext mlc = new MetadataLoadContext(new CoreMetadataAssemblyResolver())) + { + Assembly assemblyFromDisk = mlc.LoadFromAssemblyPath(file.Path); + Type typeFromDisk = assemblyFromDisk.Modules.First().GetType("MyType"); + byte[]? bodyBytes = typeFromDisk.GetMethod("Method1").GetMethodBody().GetILAsByteArray(); + Assert.Equal((byte)OpCodes.Ldarg_1.Value, bodyBytes[0]); + Assert.Equal((byte)OpCodes.Switch.Value, bodyBytes[1]); + Assert.Equal(5, bodyBytes[2]); // case count + Assert.Equal(69, bodyBytes.Length); + } } } @@ -378,8 +398,8 @@ public void LocalBuilderMultipleLocalsUsage() { using (TempFile file = TempFile.Create()) { - AssemblyBuilder ab = AssemblySaveTools.PopulateAssemblyBuilderTypeBuilderAndSaveMethod(out TypeBuilder type, out MethodInfo saveMethod); - MethodBuilder methodBuilder = type.DefineMethod("Method1", MethodAttributes.Public | MethodAttributes.Static, typeof(int), new[] { typeof(int), typeof(string) }); + AssemblyBuilder ab = AssemblySaveTools.PopulateAssemblyBuilderAndTypeBuilder(out TypeBuilder type); + MethodBuilder methodBuilder = type.DefineMethod("Method1", MethodAttributes.Public | MethodAttributes.Static, typeof(int), [typeof(int), typeof(string)]); ILGenerator il = methodBuilder.GetILGenerator(); LocalBuilder intLocal = il.DeclareLocal(typeof(int)); LocalBuilder stringLocal = il.DeclareLocal(typeof(string)); @@ -407,50 +427,53 @@ public void LocalBuilderMultipleLocalsUsage() type.CreateType(); MethodInfo getMaxStackMethod = GetMaxStackMethod(); Assert.Equal(2, getMaxStackMethod.Invoke(il, null)); - saveMethod.Invoke(ab, new object[] { file.Path }); - - Assembly assemblyFromDisk = AssemblySaveTools.LoadAssemblyFromPath(file.Path); - Type typeFromDisk = assemblyFromDisk.Modules.First().GetType("MyType"); - MethodBody body = typeFromDisk.GetMethod("Method1").GetMethodBody(); - Assert.Equal(4, body.LocalVariables.Count); - Assert.Equal(intLocal.LocalIndex, body.LocalVariables[0].LocalIndex); - Assert.Equal(intLocal.LocalType.FullName, body.LocalVariables[0].LocalType.FullName); - Assert.Equal(intLocal.IsPinned, body.LocalVariables[0].IsPinned); - Assert.Equal(stringLocal.LocalIndex, body.LocalVariables[1].LocalIndex); - Assert.Equal(stringLocal.LocalType.FullName, body.LocalVariables[1].LocalType.FullName); - Assert.Equal(stringLocal.IsPinned, body.LocalVariables[1].IsPinned); - Assert.Equal(shortLocal.LocalIndex, body.LocalVariables[2].LocalIndex); - Assert.Equal(shortLocal.LocalType.FullName, body.LocalVariables[2].LocalType.FullName); - Assert.Equal(shortLocal.IsPinned, body.LocalVariables[2].IsPinned); - Assert.Equal(int2Local.LocalIndex, body.LocalVariables[3].LocalIndex); - Assert.Equal(int2Local.LocalType.FullName, body.LocalVariables[3].LocalType.FullName); - Assert.Equal(int2Local.IsPinned, body.LocalVariables[3].IsPinned); - byte[]? bodyBytes = body.GetILAsByteArray(); - Assert.Equal((byte)OpCodes.Ldarg_1.Value, bodyBytes[0]); - Assert.Equal((byte)OpCodes.Stloc_1.Value, bodyBytes[1]); - Assert.Equal((byte)OpCodes.Ldstr.Value, bodyBytes[2]); - Assert.Equal((byte)OpCodes.Stloc_1.Value, bodyBytes[7]); - Assert.Equal((byte)OpCodes.Ldloc_1.Value, bodyBytes[8]); - Assert.Equal((byte)OpCodes.Starg_S.Value, bodyBytes[9]); - Assert.Equal((byte)OpCodes.Ldarg_0.Value, bodyBytes[11]); - Assert.Equal((byte)OpCodes.Stloc_0.Value, bodyBytes[12]); - Assert.Equal((byte)OpCodes.Ldc_I4_S.Value, bodyBytes[13]); - Assert.Equal(120, BinaryPrimitives.ReadInt32LittleEndian(bodyBytes.AsSpan().Slice(14, 4))); - Assert.Equal(0xFE, bodyBytes[18]); // Stloc instruction occupies 2 bytes 0xfe0e - Assert.Equal(0x0E, bodyBytes[19]); - Assert.Equal(2, BinaryPrimitives.ReadInt32LittleEndian(bodyBytes.AsSpan().Slice(20, 4))); // index 2 of 'il.Emit(OpCodes.Stloc, 2);' instruction - Assert.Equal((byte)OpCodes.Ldloc_2.Value, bodyBytes[24]); - Assert.Equal(0xFE, bodyBytes[25]); // Ldloc = 0xfe0c - Assert.Equal(0x0C, bodyBytes[26]); - Assert.Equal(0, BinaryPrimitives.ReadInt32LittleEndian(bodyBytes.AsSpan().Slice(27, 4))); // index 0 of 'il.Emit(OpCodes.Ldloc, 0);' instruction - Assert.Equal((byte)OpCodes.Add.Value, bodyBytes[31]); - Assert.Equal((byte)OpCodes.Stloc_0.Value, bodyBytes[32]); - Assert.Equal((byte)OpCodes.Ldloca_S.Value, bodyBytes[33]); - Assert.Equal(0, bodyBytes[34]); // intLocal index is 0 for 'il.Emit(OpCodes.Ldloca, intLocal);' instruction - Assert.Equal((byte)OpCodes.Ldind_I.Value, bodyBytes[35]); - Assert.Equal((byte)OpCodes.Stloc_3.Value, bodyBytes[36]); - Assert.Equal((byte)OpCodes.Ldloc_3.Value, bodyBytes[37]); - Assert.Equal(OpCodes.Ret.Value, bodyBytes[38]); + ab.Save(file.Path); + + using (MetadataLoadContext mlc = new MetadataLoadContext(new CoreMetadataAssemblyResolver())) + { + Assembly assemblyFromDisk = mlc.LoadFromAssemblyPath(file.Path); + Type typeFromDisk = assemblyFromDisk.Modules.First().GetType("MyType"); + MethodBody body = typeFromDisk.GetMethod("Method1").GetMethodBody(); + Assert.Equal(4, body.LocalVariables.Count); + Assert.Equal(intLocal.LocalIndex, body.LocalVariables[0].LocalIndex); + Assert.Equal(intLocal.LocalType.FullName, body.LocalVariables[0].LocalType.FullName); + Assert.Equal(intLocal.IsPinned, body.LocalVariables[0].IsPinned); + Assert.Equal(stringLocal.LocalIndex, body.LocalVariables[1].LocalIndex); + Assert.Equal(stringLocal.LocalType.FullName, body.LocalVariables[1].LocalType.FullName); + Assert.Equal(stringLocal.IsPinned, body.LocalVariables[1].IsPinned); + Assert.Equal(shortLocal.LocalIndex, body.LocalVariables[2].LocalIndex); + Assert.Equal(shortLocal.LocalType.FullName, body.LocalVariables[2].LocalType.FullName); + Assert.Equal(shortLocal.IsPinned, body.LocalVariables[2].IsPinned); + Assert.Equal(int2Local.LocalIndex, body.LocalVariables[3].LocalIndex); + Assert.Equal(int2Local.LocalType.FullName, body.LocalVariables[3].LocalType.FullName); + Assert.Equal(int2Local.IsPinned, body.LocalVariables[3].IsPinned); + byte[]? bodyBytes = body.GetILAsByteArray(); + Assert.Equal((byte)OpCodes.Ldarg_1.Value, bodyBytes[0]); + Assert.Equal((byte)OpCodes.Stloc_1.Value, bodyBytes[1]); + Assert.Equal((byte)OpCodes.Ldstr.Value, bodyBytes[2]); + Assert.Equal((byte)OpCodes.Stloc_1.Value, bodyBytes[7]); + Assert.Equal((byte)OpCodes.Ldloc_1.Value, bodyBytes[8]); + Assert.Equal((byte)OpCodes.Starg_S.Value, bodyBytes[9]); + Assert.Equal((byte)OpCodes.Ldarg_0.Value, bodyBytes[11]); + Assert.Equal((byte)OpCodes.Stloc_0.Value, bodyBytes[12]); + Assert.Equal((byte)OpCodes.Ldc_I4_S.Value, bodyBytes[13]); + Assert.Equal(120, BinaryPrimitives.ReadInt32LittleEndian(bodyBytes.AsSpan().Slice(14, 4))); + Assert.Equal(0xFE, bodyBytes[18]); // Stloc instruction occupies 2 bytes 0xfe0e + Assert.Equal(0x0E, bodyBytes[19]); + Assert.Equal(2, BinaryPrimitives.ReadInt32LittleEndian(bodyBytes.AsSpan().Slice(20, 4))); // index 2 of 'il.Emit(OpCodes.Stloc, 2);' instruction + Assert.Equal((byte)OpCodes.Ldloc_2.Value, bodyBytes[24]); + Assert.Equal(0xFE, bodyBytes[25]); // Ldloc = 0xfe0c + Assert.Equal(0x0C, bodyBytes[26]); + Assert.Equal(0, BinaryPrimitives.ReadInt32LittleEndian(bodyBytes.AsSpan().Slice(27, 4))); // index 0 of 'il.Emit(OpCodes.Ldloc, 0);' instruction + Assert.Equal((byte)OpCodes.Add.Value, bodyBytes[31]); + Assert.Equal((byte)OpCodes.Stloc_0.Value, bodyBytes[32]); + Assert.Equal((byte)OpCodes.Ldloca_S.Value, bodyBytes[33]); + Assert.Equal(0, bodyBytes[34]); // intLocal index is 0 for 'il.Emit(OpCodes.Ldloca, intLocal);' instruction + Assert.Equal((byte)OpCodes.Ldind_I.Value, bodyBytes[35]); + Assert.Equal((byte)OpCodes.Stloc_3.Value, bodyBytes[36]); + Assert.Equal((byte)OpCodes.Ldloc_3.Value, bodyBytes[37]); + Assert.Equal(OpCodes.Ret.Value, bodyBytes[38]); + } } } @@ -459,8 +482,8 @@ public void LocalBuilderMultipleTypesWithMultipleMethodsWithLocals() { using (TempFile file = TempFile.Create()) { - AssemblyBuilder ab = AssemblySaveTools.PopulateAssemblyBuilderTypeBuilderAndSaveMethod(out TypeBuilder type, out MethodInfo saveMethod); - MethodBuilder methodBuilder = type.DefineMethod("Method1", MethodAttributes.Public | MethodAttributes.Static, typeof(string), new[] { typeof(int), typeof(string) }); + AssemblyBuilder ab = AssemblySaveTools.PopulateAssemblyBuilderAndTypeBuilder(out TypeBuilder type); + MethodBuilder methodBuilder = type.DefineMethod("Method1", MethodAttributes.Public | MethodAttributes.Static, typeof(string), [typeof(int), typeof(string)]); ILGenerator il = methodBuilder.GetILGenerator(); LocalBuilder intLocal = il.DeclareLocal(typeof(int)); LocalBuilder stringLocal = il.DeclareLocal(typeof(string)); @@ -479,7 +502,7 @@ public void LocalBuilderMultipleTypesWithMultipleMethodsWithLocals() il.Emit(OpCodes.Stloc, intLocal); il.Emit(OpCodes.Ldloc, stringLocal); il.Emit(OpCodes.Ret); - MethodBuilder multiplyMethod = type.DefineMethod("MultiplyMethod", MethodAttributes.Public, typeof(int), new[] { typeof(int) }); + MethodBuilder multiplyMethod = type.DefineMethod("MultiplyMethod", MethodAttributes.Public, typeof(int), [typeof(int)]); ILGenerator multiplyMethodIL = multiplyMethod.GetILGenerator(); LocalBuilder iLocal = multiplyMethodIL.DeclareLocal(typeof(int)); LocalBuilder shLocal = multiplyMethodIL.DeclareLocal(typeof(short)); @@ -527,24 +550,27 @@ public void LocalBuilderMultipleTypesWithMultipleMethodsWithLocals() longMethodIL.Emit(OpCodes.Ldloc, longLocal); longMethodIL.Emit(OpCodes.Ret); anotherType.CreateType(); - saveMethod.Invoke(ab, new object[] { file.Path }); - - Assembly assemblyFromDisk = AssemblySaveTools.LoadAssemblyFromPath(file.Path); - Module moduleFromFile = assemblyFromDisk.Modules.First(); - Type typeFromDisk = moduleFromFile.GetType("MyType"); - Assert.Equal(2, typeFromDisk.GetMethod("MultiplyMethod").GetMethodBody().LocalVariables.Count); - Assert.Equal(3, typeFromDisk.GetMethod("Method1").GetMethodBody().LocalVariables.Count); - Type anotherTypeFromDisk = moduleFromFile.GetType("AnotherType"); - Assert.Equal(1, anotherTypeFromDisk.GetMethod("StringMethod", BindingFlags.NonPublic | BindingFlags.Instance).GetMethodBody().LocalVariables.Count); - Assert.Equal(2, anotherTypeFromDisk.GetMethod("TypeMethod", BindingFlags.NonPublic | BindingFlags.Instance).GetMethodBody().LocalVariables.Count); - Assert.Equal(2, anotherTypeFromDisk.GetMethod("LongMethod", BindingFlags.NonPublic | BindingFlags.Static).GetMethodBody().LocalVariables.Count); + ab.Save(file.Path); + + using (MetadataLoadContext mlc = new MetadataLoadContext(new CoreMetadataAssemblyResolver())) + { + Assembly assemblyFromDisk = mlc.LoadFromAssemblyPath(file.Path); + Module moduleFromFile = assemblyFromDisk.Modules.First(); + Type typeFromDisk = moduleFromFile.GetType("MyType"); + Assert.Equal(2, typeFromDisk.GetMethod("MultiplyMethod").GetMethodBody().LocalVariables.Count); + Assert.Equal(3, typeFromDisk.GetMethod("Method1").GetMethodBody().LocalVariables.Count); + Type anotherTypeFromDisk = moduleFromFile.GetType("AnotherType"); + Assert.Equal(1, anotherTypeFromDisk.GetMethod("StringMethod", BindingFlags.NonPublic | BindingFlags.Instance).GetMethodBody().LocalVariables.Count); + Assert.Equal(2, anotherTypeFromDisk.GetMethod("TypeMethod", BindingFlags.NonPublic | BindingFlags.Instance).GetMethodBody().LocalVariables.Count); + Assert.Equal(2, anotherTypeFromDisk.GetMethod("LongMethod", BindingFlags.NonPublic | BindingFlags.Static).GetMethodBody().LocalVariables.Count); + } } } [Fact] public void LocalBuilderExceptions() { - AssemblyBuilder ab = AssemblySaveTools.PopulateAssemblyBuilderTypeBuilderAndSaveMethod(out TypeBuilder type, out MethodInfo saveMethod); + AssemblyBuilder ab = AssemblySaveTools.PopulateAssemblyBuilderAndTypeBuilder(out TypeBuilder type); ILGenerator il = type.DefineMethod("Method1", MethodAttributes.Public).GetILGenerator(); ILGenerator anotherIL = type.DefineMethod("AnotherMethod", MethodAttributes.Public).GetILGenerator(); LocalBuilder stringLocal = il.DeclareLocal(typeof(string)); @@ -560,8 +586,8 @@ public void ReferenceFieldInIL() { using (TempFile file = TempFile.Create()) { - AssemblyBuilder ab = AssemblySaveTools.PopulateAssemblyBuilderTypeBuilderAndSaveMethod(out TypeBuilder tb, out MethodInfo saveMethod); - MethodBuilder methodBuilder = tb.DefineMethod("Method1", MethodAttributes.Public, typeof(int), new[] { typeof(int) }); + AssemblyBuilder ab = AssemblySaveTools.PopulateAssemblyBuilderAndTypeBuilder(out TypeBuilder tb); + MethodBuilder methodBuilder = tb.DefineMethod("Method1", MethodAttributes.Public, typeof(int), [typeof(int)]); FieldBuilder fbNumber = tb.DefineField("_number", typeof(int), FieldAttributes.Private); Assert.Equal(0, fbNumber.MetadataToken); @@ -572,19 +598,22 @@ public void ReferenceFieldInIL() il.Emit(OpCodes.Mul); il.Emit(OpCodes.Ret); tb.CreateType(); - saveMethod.Invoke(ab, new object[] { file.Path }); - - Assembly assemblyFromDisk = AssemblySaveTools.LoadAssemblyFromPath(file.Path); - Type typeFromDisk = assemblyFromDisk.Modules.First().GetType("MyType"); - byte[]? bodyBytes = typeFromDisk.GetMethod("Method1").GetMethodBody().GetILAsByteArray(); - Assert.Equal(9, bodyBytes.Length); - Assert.NotEqual(0, fbNumber.MetadataToken); - Assert.Equal(OpCodes.Ldarg_0.Value, bodyBytes[0]); - Assert.Equal(OpCodes.Ldfld.Value, bodyBytes[1]); - Assert.Equal(fbNumber.MetadataToken, BinaryPrimitives.ReadInt32LittleEndian(bodyBytes.AsSpan().Slice(2, 4))); - Assert.Equal(OpCodes.Ldarg_1.Value, bodyBytes[6]); - Assert.Equal(OpCodes.Mul.Value, bodyBytes[7]); - Assert.Equal(OpCodes.Ret.Value, bodyBytes[8]); + ab.Save(file.Path); + + using (MetadataLoadContext mlc = new MetadataLoadContext(new CoreMetadataAssemblyResolver())) + { + Assembly assemblyFromDisk = mlc.LoadFromAssemblyPath(file.Path); + Type typeFromDisk = assemblyFromDisk.Modules.First().GetType("MyType"); + byte[]? bodyBytes = typeFromDisk.GetMethod("Method1").GetMethodBody().GetILAsByteArray(); + Assert.Equal(9, bodyBytes.Length); + Assert.NotEqual(0, fbNumber.MetadataToken); + Assert.Equal(OpCodes.Ldarg_0.Value, bodyBytes[0]); + Assert.Equal(OpCodes.Ldfld.Value, bodyBytes[1]); + Assert.Equal(fbNumber.MetadataToken, BinaryPrimitives.ReadInt32LittleEndian(bodyBytes.AsSpan().Slice(2, 4))); + Assert.Equal(OpCodes.Ldarg_1.Value, bodyBytes[6]); + Assert.Equal(OpCodes.Mul.Value, bodyBytes[7]); + Assert.Equal(OpCodes.Ret.Value, bodyBytes[8]); + } } } @@ -593,12 +622,12 @@ public void ReferenceFieldAndMethodsInIL() { using (TempFile file = TempFile.Create()) { - AssemblyBuilder ab = AssemblySaveTools.PopulateAssemblyBuilderTypeBuilderAndSaveMethod(out TypeBuilder tb, out MethodInfo saveMethod); - MethodBuilder methodMain = tb.DefineMethod("Main", MethodAttributes.Public, typeof(void), new[] { typeof(int) }); + AssemblyBuilder ab = AssemblySaveTools.PopulateAssemblyBuilderAndTypeBuilder(out TypeBuilder tb); + MethodBuilder methodMain = tb.DefineMethod("Main", MethodAttributes.Public, typeof(void), [typeof(int)]); FieldBuilder field = tb.DefineField("_field", typeof(int), FieldAttributes.Private); - MethodInfo writeLineString = typeof(Console).GetMethod("WriteLine", new[] { typeof(string) }); - MethodInfo writeLineObj = typeof(Console).GetMethod("WriteLine", new[] { typeof(string), typeof(object), typeof(object), typeof(object) }); - MethodBuilder methodMultiply = tb.DefineMethod("Multiply", MethodAttributes.Public, typeof(int), new[] { typeof(int) }); + MethodInfo writeLineString = typeof(Console).GetMethod("WriteLine", [typeof(string)]); + MethodInfo writeLineObj = typeof(Console).GetMethod("WriteLine", [typeof(string), typeof(object), typeof(object), typeof(object)]); + MethodBuilder methodMultiply = tb.DefineMethod("Multiply", MethodAttributes.Public, typeof(int), [typeof(int)]); /* class MyType { @@ -634,32 +663,35 @@ void Main(int a) ilMain.Emit(OpCodes.Call, writeLineObj); ilMain.Emit(OpCodes.Ret); tb.CreateType(); - saveMethod.Invoke(ab, new object[] { file.Path }); - - Assembly assemblyFromDisk = AssemblySaveTools.LoadAssemblyFromPath(file.Path); - Type typeFromDisk = assemblyFromDisk.Modules.First().GetType("MyType"); - byte[]? bodyBytes = typeFromDisk.GetMethod("Main").GetMethodBody().GetILAsByteArray(); - Assert.Equal(OpCodes.Ldstr.Value, bodyBytes[0]); - Assert.Equal(OpCodes.Call.Value, bodyBytes[5]); - // Bytes 6, 7, 8, 9 are token for writeLineString, but it is not same as the value before save - Assert.Equal(OpCodes.Ldstr.Value, bodyBytes[10]); - Assert.Equal(OpCodes.Ldarg_0.Value, bodyBytes[15]); - Assert.Equal(OpCodes.Ldfld.Value, bodyBytes[16]); - Assert.Equal(field.MetadataToken, BinaryPrimitives.ReadInt32LittleEndian(bodyBytes.AsSpan().Slice(17, 4))); - Assert.Equal(OpCodes.Box.Value, bodyBytes[21]); - int intTypeToken = BinaryPrimitives.ReadInt32LittleEndian(bodyBytes.AsSpan().Slice(22, 4)); - Assert.Equal(OpCodes.Ldarg_1.Value, bodyBytes[26]); - Assert.Equal(OpCodes.Box.Value, bodyBytes[27]); - Assert.Equal(intTypeToken, BinaryPrimitives.ReadInt32LittleEndian(bodyBytes.AsSpan().Slice(28, 4))); - Assert.Equal(OpCodes.Ldarg_0.Value, bodyBytes[32]); - Assert.Equal(OpCodes.Ldarg_1.Value, bodyBytes[33]); - Assert.Equal(OpCodes.Call.Value, bodyBytes[34]); - Assert.Equal(methodMultiply.MetadataToken, BinaryPrimitives.ReadInt32LittleEndian(bodyBytes.AsSpan().Slice(35, 4))); - Assert.Equal(OpCodes.Box.Value, bodyBytes[39]); - Assert.Equal(intTypeToken, BinaryPrimitives.ReadInt32LittleEndian(bodyBytes.AsSpan().Slice(40, 4))); - Assert.Equal(OpCodes.Call.Value, bodyBytes[44]); - // Bytes 24, 46, 47, 48 are token for writeLineObj, but it is not same as the value before save - Assert.Equal(OpCodes.Ret.Value, bodyBytes[49]); + ab.Save(file.Path); + + using (MetadataLoadContext mlc = new MetadataLoadContext(new CoreMetadataAssemblyResolver())) + { + Assembly assemblyFromDisk = mlc.LoadFromAssemblyPath(file.Path); + Type typeFromDisk = assemblyFromDisk.Modules.First().GetType("MyType"); + byte[]? bodyBytes = typeFromDisk.GetMethod("Main").GetMethodBody().GetILAsByteArray(); + Assert.Equal(OpCodes.Ldstr.Value, bodyBytes[0]); + Assert.Equal(OpCodes.Call.Value, bodyBytes[5]); + // Bytes 6, 7, 8, 9 are token for writeLineString, but it is not same as the value before save + Assert.Equal(OpCodes.Ldstr.Value, bodyBytes[10]); + Assert.Equal(OpCodes.Ldarg_0.Value, bodyBytes[15]); + Assert.Equal(OpCodes.Ldfld.Value, bodyBytes[16]); + Assert.Equal(field.MetadataToken, BinaryPrimitives.ReadInt32LittleEndian(bodyBytes.AsSpan().Slice(17, 4))); + Assert.Equal(OpCodes.Box.Value, bodyBytes[21]); + int intTypeToken = BinaryPrimitives.ReadInt32LittleEndian(bodyBytes.AsSpan().Slice(22, 4)); + Assert.Equal(OpCodes.Ldarg_1.Value, bodyBytes[26]); + Assert.Equal(OpCodes.Box.Value, bodyBytes[27]); + Assert.Equal(intTypeToken, BinaryPrimitives.ReadInt32LittleEndian(bodyBytes.AsSpan().Slice(28, 4))); + Assert.Equal(OpCodes.Ldarg_0.Value, bodyBytes[32]); + Assert.Equal(OpCodes.Ldarg_1.Value, bodyBytes[33]); + Assert.Equal(OpCodes.Call.Value, bodyBytes[34]); + Assert.Equal(methodMultiply.MetadataToken, BinaryPrimitives.ReadInt32LittleEndian(bodyBytes.AsSpan().Slice(35, 4))); + Assert.Equal(OpCodes.Box.Value, bodyBytes[39]); + Assert.Equal(intTypeToken, BinaryPrimitives.ReadInt32LittleEndian(bodyBytes.AsSpan().Slice(40, 4))); + Assert.Equal(OpCodes.Call.Value, bodyBytes[44]); + // Bytes 24, 46, 47, 48 are token for writeLineObj, but it is not same as the value before save + Assert.Equal(OpCodes.Ret.Value, bodyBytes[49]); + } } } @@ -668,13 +700,13 @@ public void ReferenceConstructedGenericMethod() { using (TempFile file = TempFile.Create()) { - AssemblyBuilder ab = AssemblySaveTools.PopulateAssemblyBuilderTypeBuilderAndSaveMethod(out TypeBuilder type, out MethodInfo saveMethod); + AssemblyBuilder ab = AssemblySaveTools.PopulateAssemblyBuilderAndTypeBuilder(out TypeBuilder type); ConstructorBuilder ctor = type.DefineDefaultConstructor(MethodAttributes.Public); MethodBuilder genericMethod = type.DefineMethod("GM", MethodAttributes.Public | MethodAttributes.Static); GenericTypeParameterBuilder[] methodParams = genericMethod.DefineGenericParameters("U"); genericMethod.SetSignature(null, null, null, new[] { methodParams[0] }, null, null); ILGenerator ilg = genericMethod.GetILGenerator(); - MethodInfo writeLineObj = typeof(Console).GetMethod("WriteLine", new[] { typeof(object) }); + MethodInfo writeLineObj = typeof(Console).GetMethod("WriteLine", [typeof(object)]); ilg.Emit(OpCodes.Ldarg_0); ilg.EmitCall(OpCodes.Call, writeLineObj, null); ilg.Emit(OpCodes.Ret); @@ -685,17 +717,20 @@ public void ReferenceConstructedGenericMethod() ilg.EmitCall(OpCodes.Call, GMOfString, null); ilg.Emit(OpCodes.Ret); type.CreateType(); - saveMethod.Invoke(ab, new[] { file.Path }); - - Assembly assemblyFromDisk = AssemblySaveTools.LoadAssemblyFromPath(file.Path); - Type typeFromDisk = assemblyFromDisk.Modules.First().GetType("MyType"); - MethodInfo genericMethodFromDisk = typeFromDisk.GetMethod("GM"); - Assert.True(genericMethodFromDisk.IsGenericMethod); - Assert.True(genericMethodFromDisk.IsGenericMethodDefinition); - byte[] ilBytes = typeFromDisk.GetMethod("Main").GetMethodBody().GetILAsByteArray(); - Assert.Equal(OpCodes.Ldstr.Value, ilBytes[0]); - Assert.Equal(OpCodes.Call.Value, ilBytes[5]); - Assert.Equal(OpCodes.Ret.Value, ilBytes[10]); + ab.Save(file.Path); + + using (MetadataLoadContext mlc = new MetadataLoadContext(new CoreMetadataAssemblyResolver())) + { + Assembly assemblyFromDisk = mlc.LoadFromAssemblyPath(file.Path); + Type typeFromDisk = assemblyFromDisk.Modules.First().GetType("MyType"); + MethodInfo genericMethodFromDisk = typeFromDisk.GetMethod("GM"); + Assert.True(genericMethodFromDisk.IsGenericMethod); + Assert.True(genericMethodFromDisk.IsGenericMethodDefinition); + byte[] ilBytes = typeFromDisk.GetMethod("Main").GetMethodBody().GetILAsByteArray(); + Assert.Equal(OpCodes.Ldstr.Value, ilBytes[0]); + Assert.Equal(OpCodes.Call.Value, ilBytes[5]); + Assert.Equal(OpCodes.Ret.Value, ilBytes[10]); + } } } @@ -704,8 +739,8 @@ public void ReferenceConstructedGenericMethodFieldOfConstructedType() { using (TempFile file = TempFile.Create()) { - AssemblyBuilder ab = AssemblySaveTools.PopulateAssemblyBuilderTypeBuilderAndSaveMethod(out TypeBuilder type, out MethodInfo saveMethod); - GenericTypeParameterBuilder[] typeParams = type.DefineGenericParameters(new[] { "T" }); + AssemblyBuilder ab = AssemblySaveTools.PopulateAssemblyBuilderAndTypeBuilder(out TypeBuilder type); + GenericTypeParameterBuilder[] typeParams = type.DefineGenericParameters(["T"]); ConstructorBuilder ctor = type.DefineDefaultConstructor(MethodAttributes.PrivateScope | MethodAttributes.Public | MethodAttributes.HideBySig | MethodAttributes.SpecialName | MethodAttributes.RTSpecialName); FieldBuilder myField = type.DefineField("Field", typeParams[0], FieldAttributes.Public); @@ -725,7 +760,7 @@ public void ReferenceConstructedGenericMethodFieldOfConstructedType() ilg.Emit(OpCodes.Ldloc_0); ilg.Emit(OpCodes.Ldfld, FieldOfU); ilg.Emit(OpCodes.Box, methodParams[0]); - MethodInfo writeLineObj = typeof(Console).GetMethod("WriteLine", new[] { typeof(object) }); + MethodInfo writeLineObj = typeof(Console).GetMethod("WriteLine", [typeof(object)]); ilg.EmitCall(OpCodes.Call, writeLineObj, null); ilg.Emit(OpCodes.Ret); type.CreateType(); @@ -759,34 +794,38 @@ public static void Main() MyType.GM("HelloWorld"); } } */ - saveMethod.Invoke(ab, new[] { file.Path }); - - Module module = AssemblySaveTools.LoadAssemblyFromPath(file.Path).Modules.First(); - Type myTypeFromDisk = module.GetType("MyType"); - Assert.True(myTypeFromDisk.IsGenericType); - Assert.True(myTypeFromDisk.IsGenericTypeDefinition); - Assert.Equal("T", myTypeFromDisk.GetGenericArguments()[0].Name); - Assert.Equal("T", myTypeFromDisk.GetField("Field").FieldType.Name); - MethodInfo genericMethodFromDisk = myTypeFromDisk.GetMethod("GM"); - Assert.True(genericMethodFromDisk.IsGenericMethod); - Assert.True(genericMethodFromDisk.IsGenericMethodDefinition); - Assert.Equal(1, genericMethodFromDisk.GetMethodBody().LocalVariables.Count); - Assert.Equal("MyType[U]", genericMethodFromDisk.GetMethodBody().LocalVariables[0].LocalType.ToString()); - byte[] gmIlBytes = genericMethodFromDisk.GetMethodBody().GetILAsByteArray(); - Assert.Equal(OpCodes.Newobj.Value, gmIlBytes[0]); - Assert.Equal(OpCodes.Stloc_0.Value, gmIlBytes[5]); - Assert.Equal(OpCodes.Ldloc_0.Value, gmIlBytes[6]); - Assert.Equal(OpCodes.Ldarg_0.Value, gmIlBytes[7]); - Assert.Equal(OpCodes.Stfld.Value, gmIlBytes[8]); - Assert.Equal(OpCodes.Ldloc_0.Value, gmIlBytes[13]); - Assert.Equal(OpCodes.Ldfld.Value, gmIlBytes[14]); - Assert.Equal(OpCodes.Box.Value, gmIlBytes[19]); - Assert.Equal(OpCodes.Call.Value, gmIlBytes[24]); - Assert.Equal(OpCodes.Ret.Value, gmIlBytes[29]); - byte[] ilBytes = module.GetType("Dummy").GetMethod("Main").GetMethodBody().GetILAsByteArray(); - Assert.Equal(OpCodes.Ldstr.Value, ilBytes[0]); - Assert.Equal(OpCodes.Call.Value, ilBytes[5]); - Assert.Equal(OpCodes.Ret.Value, ilBytes[10]); + ab.Save(file.Path); + + using (MetadataLoadContext mlc = new MetadataLoadContext(new CoreMetadataAssemblyResolver())) + { + Assembly assemblyFromDisk = mlc.LoadFromAssemblyPath(file.Path); + Module module = assemblyFromDisk.Modules.First(); + Type myTypeFromDisk = module.GetType("MyType"); + Assert.True(myTypeFromDisk.IsGenericType); + Assert.True(myTypeFromDisk.IsGenericTypeDefinition); + Assert.Equal("T", myTypeFromDisk.GetGenericArguments()[0].Name); + Assert.Equal("T", myTypeFromDisk.GetField("Field").FieldType.Name); + MethodInfo genericMethodFromDisk = myTypeFromDisk.GetMethod("GM"); + Assert.True(genericMethodFromDisk.IsGenericMethod); + Assert.True(genericMethodFromDisk.IsGenericMethodDefinition); + Assert.Equal(1, genericMethodFromDisk.GetMethodBody().LocalVariables.Count); + Assert.Equal("MyType[U]", genericMethodFromDisk.GetMethodBody().LocalVariables[0].LocalType.ToString()); + byte[] gmIlBytes = genericMethodFromDisk.GetMethodBody().GetILAsByteArray(); + Assert.Equal(OpCodes.Newobj.Value, gmIlBytes[0]); + Assert.Equal(OpCodes.Stloc_0.Value, gmIlBytes[5]); + Assert.Equal(OpCodes.Ldloc_0.Value, gmIlBytes[6]); + Assert.Equal(OpCodes.Ldarg_0.Value, gmIlBytes[7]); + Assert.Equal(OpCodes.Stfld.Value, gmIlBytes[8]); + Assert.Equal(OpCodes.Ldloc_0.Value, gmIlBytes[13]); + Assert.Equal(OpCodes.Ldfld.Value, gmIlBytes[14]); + Assert.Equal(OpCodes.Box.Value, gmIlBytes[19]); + Assert.Equal(OpCodes.Call.Value, gmIlBytes[24]); + Assert.Equal(OpCodes.Ret.Value, gmIlBytes[29]); + byte[] ilBytes = module.GetType("Dummy").GetMethod("Main").GetMethodBody().GetILAsByteArray(); + Assert.Equal(OpCodes.Ldstr.Value, ilBytes[0]); + Assert.Equal(OpCodes.Call.Value, ilBytes[5]); + Assert.Equal(OpCodes.Ret.Value, ilBytes[10]); + } } } @@ -795,7 +834,7 @@ public void EmitWriteLineMacroTest() { using (TempFile file = TempFile.Create()) { - AssemblyBuilder ab = AssemblySaveTools.PopulateAssemblyBuilderTypeBuilderAndSaveMethod(out TypeBuilder type1, out MethodInfo saveMethod); + AssemblyBuilder ab = AssemblySaveTools.PopulateAssemblyBuilderAndTypeBuilder(out TypeBuilder type1); MethodBuilder method = type1.DefineMethod("meth", MethodAttributes.Public, typeof(int), Type.EmptyTypes); FieldBuilder field = type1.DefineField("field", typeof(int), FieldAttributes.Public | FieldAttributes.Static); ILGenerator ilGenerator = method.GetILGenerator(); @@ -810,28 +849,31 @@ public void EmitWriteLineMacroTest() ilGenerator.Emit(OpCodes.Ldsfld, field); ilGenerator.Emit(OpCodes.Ret); type1.CreateType(); - saveMethod.Invoke(ab, new object[] { file.Path }); - - Assembly assemblyFromDisk = AssemblySaveTools.LoadAssemblyFromPath(file.Path); - Type typeFromDisk = assemblyFromDisk.Modules.First().GetType("MyType"); - byte[]? bodyBytes = typeFromDisk.GetMethod("meth").GetMethodBody().GetILAsByteArray(); - Assert.Equal(OpCodes.Ldc_I4_1.Value, bodyBytes[0]); - Assert.Equal(OpCodes.Stloc_0.Value, bodyBytes[1]); - Assert.Equal(OpCodes.Ldloc_0.Value, bodyBytes[2]); - Assert.Equal(OpCodes.Stsfld.Value, bodyBytes[3]); - Assert.Equal(field.MetadataToken, BinaryPrimitives.ReadInt32LittleEndian(bodyBytes.AsSpan().Slice(4, 4))); - Assert.Equal(OpCodes.Call.Value, bodyBytes[8]); - Assert.Equal(OpCodes.Ldsfld.Value, bodyBytes[13]); - Assert.Equal(field.MetadataToken, BinaryPrimitives.ReadInt32LittleEndian(bodyBytes.AsSpan().Slice(14, 4))); - Assert.Equal(OpCodes.Callvirt.Value, bodyBytes[18]); - Assert.Equal(OpCodes.Ldstr.Value, bodyBytes[23]); - Assert.Equal(OpCodes.Call.Value, bodyBytes[28]); - Assert.Equal(OpCodes.Call.Value, bodyBytes[33]); - Assert.Equal(OpCodes.Ldloc_0.Value, bodyBytes[38]); - Assert.Equal(OpCodes.Callvirt.Value, bodyBytes[39]); - Assert.Equal(OpCodes.Ldsfld.Value, bodyBytes[44]); - Assert.Equal(field.MetadataToken, BinaryPrimitives.ReadInt32LittleEndian(bodyBytes.AsSpan().Slice(45, 4))); - Assert.Equal(OpCodes.Ret.Value, bodyBytes[49]); + ab.Save(file.Path); + + using (MetadataLoadContext mlc = new MetadataLoadContext(new CoreMetadataAssemblyResolver())) + { + Assembly assemblyFromDisk = mlc.LoadFromAssemblyPath(file.Path); + Type typeFromDisk = assemblyFromDisk.Modules.First().GetType("MyType"); + byte[]? bodyBytes = typeFromDisk.GetMethod("meth").GetMethodBody().GetILAsByteArray(); + Assert.Equal(OpCodes.Ldc_I4_1.Value, bodyBytes[0]); + Assert.Equal(OpCodes.Stloc_0.Value, bodyBytes[1]); + Assert.Equal(OpCodes.Ldloc_0.Value, bodyBytes[2]); + Assert.Equal(OpCodes.Stsfld.Value, bodyBytes[3]); + Assert.Equal(field.MetadataToken, BinaryPrimitives.ReadInt32LittleEndian(bodyBytes.AsSpan().Slice(4, 4))); + Assert.Equal(OpCodes.Call.Value, bodyBytes[8]); + Assert.Equal(OpCodes.Ldsfld.Value, bodyBytes[13]); + Assert.Equal(field.MetadataToken, BinaryPrimitives.ReadInt32LittleEndian(bodyBytes.AsSpan().Slice(14, 4))); + Assert.Equal(OpCodes.Callvirt.Value, bodyBytes[18]); + Assert.Equal(OpCodes.Ldstr.Value, bodyBytes[23]); + Assert.Equal(OpCodes.Call.Value, bodyBytes[28]); + Assert.Equal(OpCodes.Call.Value, bodyBytes[33]); + Assert.Equal(OpCodes.Ldloc_0.Value, bodyBytes[38]); + Assert.Equal(OpCodes.Callvirt.Value, bodyBytes[39]); + Assert.Equal(OpCodes.Ldsfld.Value, bodyBytes[44]); + Assert.Equal(field.MetadataToken, BinaryPrimitives.ReadInt32LittleEndian(bodyBytes.AsSpan().Slice(45, 4))); + Assert.Equal(OpCodes.Ret.Value, bodyBytes[49]); + } } } @@ -840,8 +882,8 @@ public void ReferenceStaticFieldAndMethodsInIL() { using (TempFile file = TempFile.Create()) { - AssemblyBuilder ab = AssemblySaveTools.PopulateAssemblyBuilderTypeBuilderAndSaveMethod(out TypeBuilder tb, out MethodInfo saveMethod); - MethodBuilder methodMain = tb.DefineMethod("Main", MethodAttributes.Public, typeof(int), new[] { typeof(int) }); + AssemblyBuilder ab = AssemblySaveTools.PopulateAssemblyBuilderAndTypeBuilder(out TypeBuilder tb); + MethodBuilder methodMain = tb.DefineMethod("Main", MethodAttributes.Public, typeof(int), [typeof(int)]); TypeBuilder anotherType = ab.GetDynamicModule("MyModule").DefineType("AnotherType", TypeAttributes.Public); FieldBuilder field = anotherType.DefineField("StaticField", typeof(int), FieldAttributes.Public | FieldAttributes.Static); MethodBuilder staticMethod = anotherType.DefineMethod("StaticMethod", MethodAttributes.Public | MethodAttributes.Static, typeof(void), Type.EmptyTypes); @@ -869,19 +911,22 @@ void static StaticMethod() { } il.Emit(OpCodes.Ret); tb.CreateType(); anotherType.CreateType(); - saveMethod.Invoke(ab, new object[] { file.Path }); - - Assembly assemblyFromDisk = AssemblySaveTools.LoadAssemblyFromPath(file.Path); - Type typeFromDisk = assemblyFromDisk.Modules.First().GetType("MyType"); - byte[]? bodyBytes = typeFromDisk.GetMethod("Main").GetMethodBody().GetILAsByteArray(); - Assert.Equal(OpCodes.Call.Value, bodyBytes[0]); - Assert.Equal(staticMethod.MetadataToken, BinaryPrimitives.ReadInt32LittleEndian(bodyBytes.AsSpan().Slice(1, 4))); - Assert.Equal(OpCodes.Ldarg_1.Value, bodyBytes[5]); - Assert.Equal(OpCodes.Stsfld.Value, bodyBytes[6]); - Assert.Equal(field.MetadataToken, BinaryPrimitives.ReadInt32LittleEndian(bodyBytes.AsSpan().Slice(7, 4))); - Assert.Equal(OpCodes.Ldsfld.Value, bodyBytes[11]); - Assert.Equal(field.MetadataToken, BinaryPrimitives.ReadInt32LittleEndian(bodyBytes.AsSpan().Slice(12, 4))); - Assert.Equal(OpCodes.Ret.Value, bodyBytes[16]); + ab.Save(file.Path); + + using (MetadataLoadContext mlc = new MetadataLoadContext(new CoreMetadataAssemblyResolver())) + { + Assembly assemblyFromDisk = mlc.LoadFromAssemblyPath(file.Path); + Type typeFromDisk = assemblyFromDisk.Modules.First().GetType("MyType"); + byte[]? bodyBytes = typeFromDisk.GetMethod("Main").GetMethodBody().GetILAsByteArray(); + Assert.Equal(OpCodes.Call.Value, bodyBytes[0]); + Assert.Equal(staticMethod.MetadataToken, BinaryPrimitives.ReadInt32LittleEndian(bodyBytes.AsSpan().Slice(1, 4))); + Assert.Equal(OpCodes.Ldarg_1.Value, bodyBytes[5]); + Assert.Equal(OpCodes.Stsfld.Value, bodyBytes[6]); + Assert.Equal(field.MetadataToken, BinaryPrimitives.ReadInt32LittleEndian(bodyBytes.AsSpan().Slice(7, 4))); + Assert.Equal(OpCodes.Ldsfld.Value, bodyBytes[11]); + Assert.Equal(field.MetadataToken, BinaryPrimitives.ReadInt32LittleEndian(bodyBytes.AsSpan().Slice(12, 4))); + Assert.Equal(OpCodes.Ret.Value, bodyBytes[16]); + } } } @@ -890,9 +935,9 @@ public void ReferenceConstructorInIL() { using (TempFile file = TempFile.Create()) { - AssemblyBuilder ab = AssemblySaveTools.PopulateAssemblyBuilderTypeBuilderAndSaveMethod(out TypeBuilder tb, out MethodInfo saveMethod); - MethodBuilder methodBuilder = tb.DefineMethod("Method1", MethodAttributes.Public, typeof(Version), new[] { typeof(int), typeof(int) }); - ConstructorInfo ctor = typeof(Version).GetConstructor(new[] { typeof(int), typeof(int) }); + AssemblyBuilder ab = AssemblySaveTools.PopulateAssemblyBuilderAndTypeBuilder(out TypeBuilder tb); + MethodBuilder methodBuilder = tb.DefineMethod("Method1", MethodAttributes.Public, typeof(Version), [typeof(int), typeof(int)]); + ConstructorInfo ctor = typeof(Version).GetConstructor([typeof(int), typeof(int)]); ILGenerator il = methodBuilder.GetILGenerator(); il.Emit(OpCodes.Ldarg_1); @@ -900,15 +945,18 @@ public void ReferenceConstructorInIL() il.Emit(OpCodes.Newobj, ctor); il.Emit(OpCodes.Ret); tb.CreateType(); - saveMethod.Invoke(ab, new object[] { file.Path }); - - Assembly assemblyFromDisk = AssemblySaveTools.LoadAssemblyFromPath(file.Path); - Type typeFromDisk = assemblyFromDisk.Modules.First().GetType("MyType"); - byte[]? bodyBytes = typeFromDisk.GetMethod("Method1").GetMethodBody().GetILAsByteArray(); - Assert.Equal(OpCodes.Ldarg_1.Value, bodyBytes[0]); - Assert.Equal(OpCodes.Ldarg_2.Value, bodyBytes[1]); - Assert.Equal(OpCodes.Newobj.Value, bodyBytes[2]); - Assert.Equal(OpCodes.Ret.Value, bodyBytes[7]); + ab.Save(file.Path); + + using (MetadataLoadContext mlc = new MetadataLoadContext(new CoreMetadataAssemblyResolver())) + { + Assembly assemblyFromDisk = mlc.LoadFromAssemblyPath(file.Path); + Type typeFromDisk = assemblyFromDisk.Modules.First().GetType("MyType"); + byte[]? bodyBytes = typeFromDisk.GetMethod("Method1").GetMethodBody().GetILAsByteArray(); + Assert.Equal(OpCodes.Ldarg_1.Value, bodyBytes[0]); + Assert.Equal(OpCodes.Ldarg_2.Value, bodyBytes[1]); + Assert.Equal(OpCodes.Newobj.Value, bodyBytes[2]); + Assert.Equal(OpCodes.Ret.Value, bodyBytes[7]); + } } } @@ -917,7 +965,7 @@ public void ReferenceAType() { using (TempFile file = TempFile.Create()) { - AssemblyBuilder ab = AssemblySaveTools.PopulateAssemblyBuilderTypeBuilderAndSaveMethod(out TypeBuilder tb, out MethodInfo saveMethod); + AssemblyBuilder ab = AssemblySaveTools.PopulateAssemblyBuilderAndTypeBuilder(out TypeBuilder tb); MethodBuilder method = tb.DefineMethod("meth1", MethodAttributes.Public | MethodAttributes.Static, typeof(bool), Type.EmptyTypes); ILGenerator ilGenerator = method.GetILGenerator(); LocalBuilder lb0 = ilGenerator.DeclareLocal(typeof(ValueTuple)); @@ -926,24 +974,27 @@ public void ReferenceAType() ilGenerator.Emit(OpCodes.Ldc_I4, 1); ilGenerator.Emit(OpCodes.Ret); tb.CreateType(); - saveMethod.Invoke(ab, new object[] { file.Path }); - - Assembly assemblyFromDisk = AssemblySaveTools.LoadAssemblyFromPath(file.Path); - Type typeFromDisk = assemblyFromDisk.Modules.First().GetType("MyType"); - byte[]? bodyBytes = typeFromDisk.GetMethod("meth1").GetMethodBody().GetILAsByteArray(); - Assert.Equal(OpCodes.Ldloca_S.Value, bodyBytes[0]); // short form of Ldloca - Assert.Equal(0, bodyBytes[1]); - Assert.Equal(0xFE, bodyBytes[2]); // Initobj = 0xfe15 - Assert.Equal(0x15, bodyBytes[3]); - Assert.Equal(OpCodes.Ldc_I4_1.Value, bodyBytes[8]); - Assert.Equal(OpCodes.Ret.Value, bodyBytes[9]); + ab.Save(file.Path); + + using (MetadataLoadContext mlc = new MetadataLoadContext(new CoreMetadataAssemblyResolver())) + { + Assembly assemblyFromDisk = mlc.LoadFromAssemblyPath(file.Path); + Type typeFromDisk = assemblyFromDisk.Modules.First().GetType("MyType"); + byte[]? bodyBytes = typeFromDisk.GetMethod("meth1").GetMethodBody().GetILAsByteArray(); + Assert.Equal(OpCodes.Ldloca_S.Value, bodyBytes[0]); // short form of Ldloca + Assert.Equal(0, bodyBytes[1]); + Assert.Equal(0xFE, bodyBytes[2]); // Initobj = 0xfe15 + Assert.Equal(0x15, bodyBytes[3]); + Assert.Equal(OpCodes.Ldc_I4_1.Value, bodyBytes[8]); + Assert.Equal(OpCodes.Ret.Value, bodyBytes[9]); + } } } [Fact] public void MemberReferenceExceptions() { - AssemblyBuilder ab = AssemblySaveTools.PopulateAssemblyBuilderTypeBuilderAndSaveMethod(out TypeBuilder type, out MethodInfo saveMethod); + AssemblyBuilder ab = AssemblySaveTools.PopulateAssemblyBuilderAndTypeBuilder(out TypeBuilder type); MethodBuilder method = type.DefineMethod("Method1", MethodAttributes.Public); ILGenerator il = method.GetILGenerator(); MethodInfo nullMethod = null; @@ -976,8 +1027,8 @@ public void SimpleTryCatchBlock() { using (TempFile file = TempFile.Create()) { - AssemblyBuilder ab = AssemblySaveTools.PopulateAssemblyBuilderTypeBuilderAndSaveMethod(out TypeBuilder tb, out MethodInfo saveMethod); - MethodBuilder method = tb.DefineMethod("Method", MethodAttributes.Public | MethodAttributes.Static, typeof(float), new[] { typeof(int), typeof(int) }); + AssemblyBuilder ab = AssemblySaveTools.PopulateAssemblyBuilderAndTypeBuilder(out TypeBuilder tb); + MethodBuilder method = tb.DefineMethod("Method", MethodAttributes.Public | MethodAttributes.Static, typeof(float), [typeof(int), typeof(int)]); Type dBZException = typeof(DivideByZeroException); ILGenerator ilGenerator = method.GetILGenerator(); LocalBuilder local = ilGenerator.DeclareLocal(typeof(float)); @@ -997,28 +1048,31 @@ public void SimpleTryCatchBlock() tb.CreateType(); Assert.Equal(3, getMaxStackMethod.Invoke(ilGenerator, null)); - saveMethod.Invoke(ab, new object[] { file.Path }); - - Assembly assemblyFromDisk = AssemblySaveTools.LoadAssemblyFromPath(file.Path); - Type typeFromDisk = assemblyFromDisk.Modules.First().GetType("MyType"); - MethodBody body = typeFromDisk.GetMethod("Method").GetMethodBody(); - Assert.Equal(1, body.ExceptionHandlingClauses.Count); - Assert.Equal(dBZException.FullName, body.ExceptionHandlingClauses[0].CatchType.FullName); - Assert.Equal(ExceptionHandlingClauseOptions.Clause, body.ExceptionHandlingClauses[0].Flags); - byte[] bodyBytes = body.GetILAsByteArray(); - Assert.Equal(OpCodes.Ldarg_0.Value, bodyBytes[0]); - Assert.Equal(OpCodes.Ldarg_1.Value, bodyBytes[1]); - Assert.Equal(OpCodes.Div.Value, bodyBytes[2]); - Assert.Equal(OpCodes.Stloc_0.Value, bodyBytes[3]); - Assert.Equal(OpCodes.Leave.Value, bodyBytes[4]); - // Next 4 bytes 'exBlock' label location - Assert.Equal(OpCodes.Ldstr.Value, bodyBytes[9]); // "Error: division by zero" - Assert.Equal(OpCodes.Call.Value, bodyBytes[14]); // Calls Console.WriteLine - Assert.Equal(OpCodes.Ldc_R4.Value, bodyBytes[19]); - Assert.Equal(OpCodes.Stloc_0.Value, bodyBytes[24]); - Assert.Equal(OpCodes.Leave.Value, bodyBytes[25]); - Assert.Equal(OpCodes.Ldloc_0.Value, bodyBytes[30]); - Assert.Equal(OpCodes.Ret.Value, bodyBytes[31]); + ab.Save(file.Path); + + using (MetadataLoadContext mlc = new MetadataLoadContext(new CoreMetadataAssemblyResolver())) + { + Assembly assemblyFromDisk = mlc.LoadFromAssemblyPath(file.Path); + Type typeFromDisk = assemblyFromDisk.Modules.First().GetType("MyType"); + MethodBody body = typeFromDisk.GetMethod("Method").GetMethodBody(); + Assert.Equal(1, body.ExceptionHandlingClauses.Count); + Assert.Equal(dBZException.FullName, body.ExceptionHandlingClauses[0].CatchType.FullName); + Assert.Equal(ExceptionHandlingClauseOptions.Clause, body.ExceptionHandlingClauses[0].Flags); + byte[] bodyBytes = body.GetILAsByteArray(); + Assert.Equal(OpCodes.Ldarg_0.Value, bodyBytes[0]); + Assert.Equal(OpCodes.Ldarg_1.Value, bodyBytes[1]); + Assert.Equal(OpCodes.Div.Value, bodyBytes[2]); + Assert.Equal(OpCodes.Stloc_0.Value, bodyBytes[3]); + Assert.Equal(OpCodes.Leave.Value, bodyBytes[4]); + // Next 4 bytes 'exBlock' label location + Assert.Equal(OpCodes.Ldstr.Value, bodyBytes[9]); // "Error: division by zero" + Assert.Equal(OpCodes.Call.Value, bodyBytes[14]); // Calls Console.WriteLine + Assert.Equal(OpCodes.Ldc_R4.Value, bodyBytes[19]); + Assert.Equal(OpCodes.Stloc_0.Value, bodyBytes[24]); + Assert.Equal(OpCodes.Leave.Value, bodyBytes[25]); + Assert.Equal(OpCodes.Ldloc_0.Value, bodyBytes[30]); + Assert.Equal(OpCodes.Ret.Value, bodyBytes[31]); + } } } @@ -1027,8 +1081,8 @@ public void TryMultipleCatchBlocks() { using (TempFile file = TempFile.Create()) { - AssemblyBuilder ab = AssemblySaveTools.PopulateAssemblyBuilderTypeBuilderAndSaveMethod(out TypeBuilder tb, out MethodInfo saveMethod); - MethodBuilder method = tb.DefineMethod("Method", MethodAttributes.Public | MethodAttributes.Static, typeof(float), new[] { typeof(int), typeof(int) }); + AssemblyBuilder ab = AssemblySaveTools.PopulateAssemblyBuilderAndTypeBuilder(out TypeBuilder tb); + MethodBuilder method = tb.DefineMethod("Method", MethodAttributes.Public | MethodAttributes.Static, typeof(float), [typeof(int), typeof(int)]); Type dBZException = typeof(DivideByZeroException); Type exception = typeof(Exception); ILGenerator ilGenerator = method.GetILGenerator(); @@ -1058,40 +1112,43 @@ public void TryMultipleCatchBlocks() ilGenerator.Emit(OpCodes.Ldloc_0); ilGenerator.Emit(OpCodes.Ret); tb.CreateType(); - saveMethod.Invoke(ab, new object[] { file.Path }); + ab.Save(file.Path); Assert.Equal(2, maxStackField.GetValue(ilGenerator)); MethodInfo getMaxStackMethod = GetMaxStackMethod(); Assert.Equal(2, getMaxStackMethod.Invoke(ilGenerator, null)); - Assembly assemblyFromDisk = AssemblySaveTools.LoadAssemblyFromPath(file.Path); - Type typeFromDisk = assemblyFromDisk.Modules.First().GetType("MyType"); - MethodBody body = typeFromDisk.GetMethod("Method").GetMethodBody(); - Assert.Equal(2, body.ExceptionHandlingClauses.Count); - Assert.Equal(ExceptionHandlingClauseOptions.Clause, body.ExceptionHandlingClauses[0].Flags); - Assert.Equal(ExceptionHandlingClauseOptions.Clause, body.ExceptionHandlingClauses[1].Flags); - Assert.Equal(dBZException.FullName, body.ExceptionHandlingClauses[0].CatchType.FullName); - Assert.Equal(exception.FullName, body.ExceptionHandlingClauses[1].CatchType.FullName); - byte[] bodyBytes = body.GetILAsByteArray(); - Assert.Equal(OpCodes.Ldarg_0.Value, bodyBytes[0]); - Assert.Equal(OpCodes.Ldarg_1.Value, bodyBytes[1]); - Assert.Equal(OpCodes.Div.Value, bodyBytes[2]); - Assert.Equal(OpCodes.Stloc_0.Value, bodyBytes[3]); - Assert.Equal(OpCodes.Leave.Value, bodyBytes[4]); - Assert.Equal(OpCodes.Ldstr.Value, bodyBytes[9]); // "Error: division by zero" - Assert.Equal(OpCodes.Call.Value, bodyBytes[14]); // Calls Console.WriteLine - Assert.Equal(OpCodes.Ldc_R4.Value, bodyBytes[19]); - Assert.Equal(OpCodes.Stloc_0.Value, bodyBytes[24]); - Assert.Equal(OpCodes.Pop.Value, bodyBytes[25]); - Assert.Equal(OpCodes.Leave.Value, bodyBytes[26]); - Assert.Equal(OpCodes.Ldstr.Value, bodyBytes[31]); // "Error: division by zero" - Assert.Equal(OpCodes.Call.Value, bodyBytes[36]); // Calls Console.WriteLine - Assert.Equal(OpCodes.Ldc_R4.Value, bodyBytes[41]); - Assert.Equal(OpCodes.Stloc_0.Value, bodyBytes[46]); - Assert.Equal(OpCodes.Pop.Value, bodyBytes[47]); - Assert.Equal(OpCodes.Leave.Value, bodyBytes[48]); - Assert.Equal(OpCodes.Ldloc_0.Value, bodyBytes[53]); - Assert.Equal(OpCodes.Ret.Value, bodyBytes[54]); + using (MetadataLoadContext mlc = new MetadataLoadContext(new CoreMetadataAssemblyResolver())) + { + Assembly assemblyFromDisk = mlc.LoadFromAssemblyPath(file.Path); + Type typeFromDisk = assemblyFromDisk.Modules.First().GetType("MyType"); + MethodBody body = typeFromDisk.GetMethod("Method").GetMethodBody(); + Assert.Equal(2, body.ExceptionHandlingClauses.Count); + Assert.Equal(ExceptionHandlingClauseOptions.Clause, body.ExceptionHandlingClauses[0].Flags); + Assert.Equal(ExceptionHandlingClauseOptions.Clause, body.ExceptionHandlingClauses[1].Flags); + Assert.Equal(dBZException.FullName, body.ExceptionHandlingClauses[0].CatchType.FullName); + Assert.Equal(exception.FullName, body.ExceptionHandlingClauses[1].CatchType.FullName); + byte[] bodyBytes = body.GetILAsByteArray(); + Assert.Equal(OpCodes.Ldarg_0.Value, bodyBytes[0]); + Assert.Equal(OpCodes.Ldarg_1.Value, bodyBytes[1]); + Assert.Equal(OpCodes.Div.Value, bodyBytes[2]); + Assert.Equal(OpCodes.Stloc_0.Value, bodyBytes[3]); + Assert.Equal(OpCodes.Leave.Value, bodyBytes[4]); + Assert.Equal(OpCodes.Ldstr.Value, bodyBytes[9]); // "Error: division by zero" + Assert.Equal(OpCodes.Call.Value, bodyBytes[14]); // Calls Console.WriteLine + Assert.Equal(OpCodes.Ldc_R4.Value, bodyBytes[19]); + Assert.Equal(OpCodes.Stloc_0.Value, bodyBytes[24]); + Assert.Equal(OpCodes.Pop.Value, bodyBytes[25]); + Assert.Equal(OpCodes.Leave.Value, bodyBytes[26]); + Assert.Equal(OpCodes.Ldstr.Value, bodyBytes[31]); // "Error: division by zero" + Assert.Equal(OpCodes.Call.Value, bodyBytes[36]); // Calls Console.WriteLine + Assert.Equal(OpCodes.Ldc_R4.Value, bodyBytes[41]); + Assert.Equal(OpCodes.Stloc_0.Value, bodyBytes[46]); + Assert.Equal(OpCodes.Pop.Value, bodyBytes[47]); + Assert.Equal(OpCodes.Leave.Value, bodyBytes[48]); + Assert.Equal(OpCodes.Ldloc_0.Value, bodyBytes[53]); + Assert.Equal(OpCodes.Ret.Value, bodyBytes[54]); + } } } @@ -1100,8 +1157,8 @@ public void TryFilterCatchBlock() { using (TempFile file = TempFile.Create()) { - AssemblyBuilder ab = AssemblySaveTools.PopulateAssemblyBuilderTypeBuilderAndSaveMethod(out TypeBuilder tb, out MethodInfo saveMethod); - MethodBuilder method = tb.DefineMethod("Method", MethodAttributes.Public | MethodAttributes.Static, typeof(float), new[] { typeof(int), typeof(int) }); + AssemblyBuilder ab = AssemblySaveTools.PopulateAssemblyBuilderAndTypeBuilder(out TypeBuilder tb); + MethodBuilder method = tb.DefineMethod("Method", MethodAttributes.Public | MethodAttributes.Static, typeof(float), [typeof(int), typeof(int)]); Type dBZException = typeof(DivideByZeroException); Type exception = typeof(Exception); ILGenerator ilGenerator = method.GetILGenerator(); @@ -1140,18 +1197,21 @@ public void TryFilterCatchBlock() ilGenerator.Emit(OpCodes.Ldloc_0); ilGenerator.Emit(OpCodes.Ret); tb.CreateType(); - saveMethod.Invoke(ab, new object[] { file.Path }); + ab.Save(file.Path); MethodInfo getMaxStackMethod = GetMaxStackMethod(); Assert.Equal(2, getMaxStackMethod.Invoke(ilGenerator, null)); - Assembly assemblyFromDisk = AssemblySaveTools.LoadAssemblyFromPath(file.Path); - Type typeFromDisk = assemblyFromDisk.Modules.First().GetType("MyType"); - MethodBody body = typeFromDisk.GetMethod("Method").GetMethodBody(); - Assert.Equal(2, body.ExceptionHandlingClauses.Count); - Assert.Equal(ExceptionHandlingClauseOptions.Filter, body.ExceptionHandlingClauses[0].Flags); - Assert.Equal(ExceptionHandlingClauseOptions.Clause, body.ExceptionHandlingClauses[1].Flags); - Assert.Equal(exception.FullName, body.ExceptionHandlingClauses[1].CatchType.FullName); + using (MetadataLoadContext mlc = new MetadataLoadContext(new CoreMetadataAssemblyResolver())) + { + Assembly assemblyFromDisk = mlc.LoadFromAssemblyPath(file.Path); + Type typeFromDisk = assemblyFromDisk.Modules.First().GetType("MyType"); + MethodBody body = typeFromDisk.GetMethod("Method").GetMethodBody(); + Assert.Equal(2, body.ExceptionHandlingClauses.Count); + Assert.Equal(ExceptionHandlingClauseOptions.Filter, body.ExceptionHandlingClauses[0].Flags); + Assert.Equal(ExceptionHandlingClauseOptions.Clause, body.ExceptionHandlingClauses[1].Flags); + Assert.Equal(exception.FullName, body.ExceptionHandlingClauses[1].CatchType.FullName); + } } } @@ -1160,8 +1220,8 @@ public void TryCatchFilterCatchBlock() { using (TempFile file = TempFile.Create()) { - AssemblyBuilder ab = AssemblySaveTools.PopulateAssemblyBuilderTypeBuilderAndSaveMethod(out TypeBuilder tb, out MethodInfo saveMethod); - MethodBuilder method = tb.DefineMethod("Method", MethodAttributes.Public | MethodAttributes.Static, typeof(float), new[] { typeof(int), typeof(int) }); + AssemblyBuilder ab = AssemblySaveTools.PopulateAssemblyBuilderAndTypeBuilder(out TypeBuilder tb); + MethodBuilder method = tb.DefineMethod("Method", MethodAttributes.Public | MethodAttributes.Static, typeof(float), [typeof(int), typeof(int)]); Type dBZException = typeof(DivideByZeroException); Type overflowException = typeof(OverflowException); Type exception = typeof(Exception); @@ -1177,7 +1237,7 @@ public void TryCatchFilterCatchBlock() ilGenerator.Emit(OpCodes.Ldarg_1); ilGenerator.Emit(OpCodes.Div); ilGenerator.Emit(OpCodes.Stloc_0); - Assert.Equal(2, maxStackField.GetValue(ilGenerator)); + Assert.Equal(2, maxStackField.GetValue(ilGenerator)); ilGenerator.BeginCatchBlock(overflowException); ilGenerator.EmitWriteLine("Overflow Exception!"); ilGenerator.ThrowException(overflowException); @@ -1210,20 +1270,23 @@ public void TryCatchFilterCatchBlock() ilGenerator.Emit(OpCodes.Ldloc_0); ilGenerator.Emit(OpCodes.Ret); tb.CreateType(); - saveMethod.Invoke(ab, new object[] { file.Path }); + ab.Save(file.Path); MethodInfo getMaxStackMethod = GetMaxStackMethod(); Assert.Equal(2, getMaxStackMethod.Invoke(ilGenerator, null)); - Assembly assemblyFromDisk = AssemblySaveTools.LoadAssemblyFromPath(file.Path); - Type typeFromDisk = assemblyFromDisk.Modules.First().GetType("MyType"); - MethodBody body = typeFromDisk.GetMethod("Method").GetMethodBody(); - Assert.Equal(3, body.ExceptionHandlingClauses.Count); - Assert.Equal(ExceptionHandlingClauseOptions.Clause, body.ExceptionHandlingClauses[0].Flags); - Assert.Equal(ExceptionHandlingClauseOptions.Filter, body.ExceptionHandlingClauses[1].Flags); - Assert.Equal(ExceptionHandlingClauseOptions.Clause, body.ExceptionHandlingClauses[2].Flags); - Assert.Equal(overflowException.FullName, body.ExceptionHandlingClauses[0].CatchType.FullName); - Assert.Equal(exception.FullName, body.ExceptionHandlingClauses[2].CatchType.FullName); + using (MetadataLoadContext mlc = new MetadataLoadContext(new CoreMetadataAssemblyResolver())) + { + Assembly assemblyFromDisk = mlc.LoadFromAssemblyPath(file.Path); + Type typeFromDisk = assemblyFromDisk.Modules.First().GetType("MyType"); + MethodBody body = typeFromDisk.GetMethod("Method").GetMethodBody(); + Assert.Equal(3, body.ExceptionHandlingClauses.Count); + Assert.Equal(ExceptionHandlingClauseOptions.Clause, body.ExceptionHandlingClauses[0].Flags); + Assert.Equal(ExceptionHandlingClauseOptions.Filter, body.ExceptionHandlingClauses[1].Flags); + Assert.Equal(ExceptionHandlingClauseOptions.Clause, body.ExceptionHandlingClauses[2].Flags); + Assert.Equal(overflowException.FullName, body.ExceptionHandlingClauses[0].CatchType.FullName); + Assert.Equal(exception.FullName, body.ExceptionHandlingClauses[2].CatchType.FullName); + } } } @@ -1232,8 +1295,8 @@ public void TryFinallyBlock() { using (TempFile file = TempFile.Create()) { - AssemblyBuilder ab = AssemblySaveTools.PopulateAssemblyBuilderTypeBuilderAndSaveMethod(out TypeBuilder tb, out MethodInfo saveMethod); - MethodBuilder method = tb.DefineMethod("Method", MethodAttributes.Public | MethodAttributes.Static, typeof(float), new[] { typeof(int), typeof(int) }); + AssemblyBuilder ab = AssemblySaveTools.PopulateAssemblyBuilderAndTypeBuilder(out TypeBuilder tb); + MethodBuilder method = tb.DefineMethod("Method", MethodAttributes.Public | MethodAttributes.Static, typeof(float), [typeof(int), typeof(int)]); ILGenerator ilGenerator = method.GetILGenerator(); LocalBuilder local = ilGenerator.DeclareLocal(typeof(float)); Label exBlock = ilGenerator.BeginExceptionBlock(); @@ -1247,27 +1310,30 @@ public void TryFinallyBlock() ilGenerator.Emit(OpCodes.Ldloc_0); ilGenerator.Emit(OpCodes.Ret); tb.CreateType(); - saveMethod.Invoke(ab, new object[] { file.Path }); + ab.Save(file.Path); MethodInfo getMaxStackMethod = GetMaxStackMethod(); Assert.Equal(2, getMaxStackMethod.Invoke(ilGenerator, null)); - Assembly assemblyFromDisk = AssemblySaveTools.LoadAssemblyFromPath(file.Path); - Type typeFromDisk = assemblyFromDisk.Modules.First().GetType("MyType"); - MethodBody body = typeFromDisk.GetMethod("Method").GetMethodBody(); - Assert.Equal(1, body.ExceptionHandlingClauses.Count); - Assert.Equal(ExceptionHandlingClauseOptions.Finally, body.ExceptionHandlingClauses[0].Flags); - byte[] bodyBytes = body.GetILAsByteArray(); - Assert.Equal(OpCodes.Ldarg_0.Value, bodyBytes[0]); - Assert.Equal(OpCodes.Ldarg_1.Value, bodyBytes[1]); - Assert.Equal(OpCodes.Div.Value, bodyBytes[2]); - Assert.Equal(OpCodes.Stloc_0.Value, bodyBytes[3]); - Assert.Equal(OpCodes.Leave.Value, bodyBytes[4]); - Assert.Equal(OpCodes.Ldstr.Value, bodyBytes[9]); - Assert.Equal(OpCodes.Call.Value, bodyBytes[14]); - Assert.Equal(OpCodes.Endfinally.Value, bodyBytes[19]); - Assert.Equal(OpCodes.Ldloc_0.Value, bodyBytes[20]); - Assert.Equal(OpCodes.Ret.Value, bodyBytes[21]); + using (MetadataLoadContext mlc = new MetadataLoadContext(new CoreMetadataAssemblyResolver())) + { + Assembly assemblyFromDisk = mlc.LoadFromAssemblyPath(file.Path); + Type typeFromDisk = assemblyFromDisk.Modules.First().GetType("MyType"); + MethodBody body = typeFromDisk.GetMethod("Method").GetMethodBody(); + Assert.Equal(1, body.ExceptionHandlingClauses.Count); + Assert.Equal(ExceptionHandlingClauseOptions.Finally, body.ExceptionHandlingClauses[0].Flags); + byte[] bodyBytes = body.GetILAsByteArray(); + Assert.Equal(OpCodes.Ldarg_0.Value, bodyBytes[0]); + Assert.Equal(OpCodes.Ldarg_1.Value, bodyBytes[1]); + Assert.Equal(OpCodes.Div.Value, bodyBytes[2]); + Assert.Equal(OpCodes.Stloc_0.Value, bodyBytes[3]); + Assert.Equal(OpCodes.Leave.Value, bodyBytes[4]); + Assert.Equal(OpCodes.Ldstr.Value, bodyBytes[9]); + Assert.Equal(OpCodes.Call.Value, bodyBytes[14]); + Assert.Equal(OpCodes.Endfinally.Value, bodyBytes[19]); + Assert.Equal(OpCodes.Ldloc_0.Value, bodyBytes[20]); + Assert.Equal(OpCodes.Ret.Value, bodyBytes[21]); + } } } @@ -1276,8 +1342,8 @@ public void TryCatchFinallyBlock() { using (TempFile file = TempFile.Create()) { - AssemblyBuilder ab = AssemblySaveTools.PopulateAssemblyBuilderTypeBuilderAndSaveMethod(out TypeBuilder tb, out MethodInfo saveMethod); - MethodBuilder method = tb.DefineMethod("Method", MethodAttributes.Public | MethodAttributes.Static, typeof(void), new[] { typeof(int), typeof(int) }); + AssemblyBuilder ab = AssemblySaveTools.PopulateAssemblyBuilderAndTypeBuilder(out TypeBuilder tb); + MethodBuilder method = tb.DefineMethod("Method", MethodAttributes.Public | MethodAttributes.Static, typeof(void), [typeof(int), typeof(int)]); Type exception = typeof(Exception); ILGenerator ilGenerator = method.GetILGenerator(); ilGenerator.BeginExceptionBlock(); @@ -1291,18 +1357,21 @@ public void TryCatchFinallyBlock() ilGenerator.EndExceptionBlock(); ilGenerator.Emit(OpCodes.Ret); tb.CreateType(); - saveMethod.Invoke(ab, new object[] { file.Path }); + ab.Save(file.Path); MethodInfo getMaxStackMethod = GetMaxStackMethod(); Assert.Equal(2, getMaxStackMethod.Invoke(ilGenerator, null)); - Assembly assemblyFromDisk = AssemblySaveTools.LoadAssemblyFromPath(file.Path); - Type typeFromDisk = assemblyFromDisk.Modules.First().GetType("MyType"); - MethodBody body = typeFromDisk.GetMethod("Method").GetMethodBody(); - Assert.Equal(2, body.ExceptionHandlingClauses.Count); - Assert.Equal(ExceptionHandlingClauseOptions.Clause, body.ExceptionHandlingClauses[0].Flags); - Assert.Equal(ExceptionHandlingClauseOptions.Finally, body.ExceptionHandlingClauses[1].Flags); - Assert.Equal(exception.FullName, body.ExceptionHandlingClauses[0].CatchType.FullName); + using (MetadataLoadContext mlc = new MetadataLoadContext(new CoreMetadataAssemblyResolver())) + { + Assembly assemblyFromDisk = mlc.LoadFromAssemblyPath(file.Path); + Type typeFromDisk = assemblyFromDisk.Modules.First().GetType("MyType"); + MethodBody body = typeFromDisk.GetMethod("Method").GetMethodBody(); + Assert.Equal(2, body.ExceptionHandlingClauses.Count); + Assert.Equal(ExceptionHandlingClauseOptions.Clause, body.ExceptionHandlingClauses[0].Flags); + Assert.Equal(ExceptionHandlingClauseOptions.Finally, body.ExceptionHandlingClauses[1].Flags); + Assert.Equal(exception.FullName, body.ExceptionHandlingClauses[0].CatchType.FullName); + } } } @@ -1311,12 +1380,12 @@ public void TryFilterCatchFinallyBlock() { using (TempFile file = TempFile.Create()) { - AssemblyBuilder ab = AssemblySaveTools.PopulateAssemblyBuilderTypeBuilderAndSaveMethod(out TypeBuilder tb, out MethodInfo saveMethod); - MethodBuilder method = tb.DefineMethod("Method", MethodAttributes.Public | MethodAttributes.Static, typeof(int), new[] { typeof(int), typeof(int) }); + AssemblyBuilder ab = AssemblySaveTools.PopulateAssemblyBuilderAndTypeBuilder(out TypeBuilder tb); + MethodBuilder method = tb.DefineMethod("Method", MethodAttributes.Public | MethodAttributes.Static, typeof(int), [typeof(int), typeof(int)]); Type overflowEType = typeof(OverflowException); - ConstructorInfo myConstructorInfo = overflowEType.GetConstructor(new [] { typeof(string) }); + ConstructorInfo myConstructorInfo = overflowEType.GetConstructor([typeof(string)]); MethodInfo myExToStrMI = overflowEType.GetMethod("ToString"); - MethodInfo myWriteLineMI = typeof(Console).GetMethod("WriteLine", new [] {typeof(string),typeof(object) }); + MethodInfo myWriteLineMI = typeof(Console).GetMethod("WriteLine", [typeof(string), typeof(object)]); ILGenerator ilGenerator = method.GetILGenerator(); LocalBuilder myLocalBuilder1 = ilGenerator.DeclareLocal(typeof(int)); LocalBuilder myLocalBuilder2 = ilGenerator.DeclareLocal(overflowEType); @@ -1360,19 +1429,22 @@ public void TryFilterCatchFinallyBlock() ilGenerator.Emit(OpCodes.Ldloc_S, myLocalBuilder1); ilGenerator.Emit(OpCodes.Ret); tb.CreateType(); - saveMethod.Invoke(ab, new object[] { file.Path }); + ab.Save(file.Path); MethodInfo getMaxStackMethod = GetMaxStackMethod(); Assert.Equal(2, getMaxStackMethod.Invoke(ilGenerator, null)); - Assembly assemblyFromDisk = AssemblySaveTools.LoadAssemblyFromPath(file.Path); - Type typeFromDisk = assemblyFromDisk.Modules.First().GetType("MyType"); - MethodBody body = typeFromDisk.GetMethod("Method").GetMethodBody(); - Assert.Equal(3, body.ExceptionHandlingClauses.Count); - Assert.Equal(ExceptionHandlingClauseOptions.Filter, body.ExceptionHandlingClauses[0].Flags); - Assert.Equal(ExceptionHandlingClauseOptions.Clause, body.ExceptionHandlingClauses[1].Flags); - Assert.Equal(ExceptionHandlingClauseOptions.Finally, body.ExceptionHandlingClauses[2].Flags); - Assert.Equal(overflowEType.FullName, body.ExceptionHandlingClauses[1].CatchType.FullName); + using (MetadataLoadContext mlc = new MetadataLoadContext(new CoreMetadataAssemblyResolver())) + { + Assembly assemblyFromDisk = mlc.LoadFromAssemblyPath(file.Path); + Type typeFromDisk = assemblyFromDisk.Modules.First().GetType("MyType"); + MethodBody body = typeFromDisk.GetMethod("Method").GetMethodBody(); + Assert.Equal(3, body.ExceptionHandlingClauses.Count); + Assert.Equal(ExceptionHandlingClauseOptions.Filter, body.ExceptionHandlingClauses[0].Flags); + Assert.Equal(ExceptionHandlingClauseOptions.Clause, body.ExceptionHandlingClauses[1].Flags); + Assert.Equal(ExceptionHandlingClauseOptions.Finally, body.ExceptionHandlingClauses[2].Flags); + Assert.Equal(overflowEType.FullName, body.ExceptionHandlingClauses[1].CatchType.FullName); + } } } @@ -1381,8 +1453,8 @@ public void TryFaultBlock() { using (TempFile file = TempFile.Create()) { - AssemblyBuilder ab = AssemblySaveTools.PopulateAssemblyBuilderTypeBuilderAndSaveMethod(out TypeBuilder tb, out MethodInfo saveMethod); - MethodBuilder method = tb.DefineMethod("Method", MethodAttributes.Public | MethodAttributes.Static, typeof(float), new[] { typeof(int), typeof(int) }); + AssemblyBuilder ab = AssemblySaveTools.PopulateAssemblyBuilderAndTypeBuilder(out TypeBuilder tb); + MethodBuilder method = tb.DefineMethod("Method", MethodAttributes.Public | MethodAttributes.Static, typeof(float), [typeof(int), typeof(int)]); ILGenerator ilGenerator = method.GetILGenerator(); Label exBlock = ilGenerator.BeginExceptionBlock(); ilGenerator.Emit(OpCodes.Ldarg_0); @@ -1397,29 +1469,32 @@ public void TryFaultBlock() ilGenerator.Emit(OpCodes.Ldloc_0); ilGenerator.Emit(OpCodes.Ret); tb.CreateType(); - saveMethod.Invoke(ab, new object[] { file.Path }); + ab.Save(file.Path); MethodInfo getMaxStackMethod = GetMaxStackMethod(); Assert.Equal(2, getMaxStackMethod.Invoke(ilGenerator, null)); - Assembly assemblyFromDisk = AssemblySaveTools.LoadAssemblyFromPath(file.Path); - Type typeFromDisk = assemblyFromDisk.Modules.First().GetType("MyType"); - MethodBody body = typeFromDisk.GetMethod("Method").GetMethodBody(); - Assert.Equal(1, body.ExceptionHandlingClauses.Count); - Assert.Equal(ExceptionHandlingClauseOptions.Fault, body.ExceptionHandlingClauses[0].Flags); - byte[] bodyBytes = body.GetILAsByteArray(); - Assert.Equal(OpCodes.Ldarg_0.Value, bodyBytes[0]); - Assert.Equal(OpCodes.Ldarg_1.Value, bodyBytes[1]); - Assert.Equal(OpCodes.Div.Value, bodyBytes[2]); - Assert.Equal(OpCodes.Stloc_0.Value, bodyBytes[3]); - Assert.Equal(OpCodes.Leave.Value, bodyBytes[4]); - Assert.Equal(OpCodes.Ldstr.Value, bodyBytes[9]); - Assert.Equal(OpCodes.Call.Value, bodyBytes[14]); - Assert.Equal(OpCodes.Ldc_R4.Value, bodyBytes[19]); - Assert.Equal(OpCodes.Stloc_0.Value, bodyBytes[24]); - Assert.Equal(OpCodes.Endfinally.Value, bodyBytes[25]); - Assert.Equal(OpCodes.Ldloc_0.Value, bodyBytes[26]); - Assert.Equal(OpCodes.Ret.Value, bodyBytes[27]); + using (MetadataLoadContext mlc = new MetadataLoadContext(new CoreMetadataAssemblyResolver())) + { + Assembly assemblyFromDisk = mlc.LoadFromAssemblyPath(file.Path); + Type typeFromDisk = assemblyFromDisk.Modules.First().GetType("MyType"); + MethodBody body = typeFromDisk.GetMethod("Method").GetMethodBody(); + Assert.Equal(1, body.ExceptionHandlingClauses.Count); + Assert.Equal(ExceptionHandlingClauseOptions.Fault, body.ExceptionHandlingClauses[0].Flags); + byte[] bodyBytes = body.GetILAsByteArray(); + Assert.Equal(OpCodes.Ldarg_0.Value, bodyBytes[0]); + Assert.Equal(OpCodes.Ldarg_1.Value, bodyBytes[1]); + Assert.Equal(OpCodes.Div.Value, bodyBytes[2]); + Assert.Equal(OpCodes.Stloc_0.Value, bodyBytes[3]); + Assert.Equal(OpCodes.Leave.Value, bodyBytes[4]); + Assert.Equal(OpCodes.Ldstr.Value, bodyBytes[9]); + Assert.Equal(OpCodes.Call.Value, bodyBytes[14]); + Assert.Equal(OpCodes.Ldc_R4.Value, bodyBytes[19]); + Assert.Equal(OpCodes.Stloc_0.Value, bodyBytes[24]); + Assert.Equal(OpCodes.Endfinally.Value, bodyBytes[25]); + Assert.Equal(OpCodes.Ldloc_0.Value, bodyBytes[26]); + Assert.Equal(OpCodes.Ret.Value, bodyBytes[27]); + } } } @@ -1428,8 +1503,8 @@ public void NestedTryCatchBlocks() { using (TempFile file = TempFile.Create()) { - AssemblyBuilder ab = AssemblySaveTools.PopulateAssemblyBuilderTypeBuilderAndSaveMethod(out TypeBuilder tb, out MethodInfo saveMethod); - MethodBuilder method = tb.DefineMethod("Method", MethodAttributes.Public | MethodAttributes.Static, typeof(void), new[] { typeof(int), typeof(int) }); + AssemblyBuilder ab = AssemblySaveTools.PopulateAssemblyBuilderAndTypeBuilder(out TypeBuilder tb); + MethodBuilder method = tb.DefineMethod("Method", MethodAttributes.Public | MethodAttributes.Static, typeof(void), [typeof(int), typeof(int)]); Type exception = typeof(Exception); ILGenerator ilGenerator = method.GetILGenerator(); MethodInfo getMaxStackMethod = GetMaxStackMethod(); @@ -1473,20 +1548,23 @@ public void NestedTryCatchBlocks() ilGenerator.EndExceptionBlock(); ilGenerator.Emit(OpCodes.Ret); tb.CreateType(); - saveMethod.Invoke(ab, new object[] { file.Path }); + ab.Save(file.Path); Assert.Equal(5, getMaxStackMethod.Invoke(ilGenerator, null)); - Assembly assemblyFromDisk = AssemblySaveTools.LoadAssemblyFromPath(file.Path); - Type typeFromDisk = assemblyFromDisk.Modules.First().GetType("MyType"); - MethodBody body = typeFromDisk.GetMethod("Method").GetMethodBody(); - Assert.Equal(3, body.ExceptionHandlingClauses.Count); - Assert.Equal(ExceptionHandlingClauseOptions.Clause, body.ExceptionHandlingClauses[0].Flags); - Assert.Equal(ExceptionHandlingClauseOptions.Clause, body.ExceptionHandlingClauses[1].Flags); - Assert.Equal(ExceptionHandlingClauseOptions.Clause, body.ExceptionHandlingClauses[2].Flags); - Assert.Equal(exception.FullName, body.ExceptionHandlingClauses[0].CatchType.FullName); - Assert.Equal(exception.FullName, body.ExceptionHandlingClauses[1].CatchType.FullName); - Assert.Equal(exception.FullName, body.ExceptionHandlingClauses[2].CatchType.FullName); + using (MetadataLoadContext mlc = new MetadataLoadContext(new CoreMetadataAssemblyResolver())) + { + Assembly assemblyFromDisk = mlc.LoadFromAssemblyPath(file.Path); + Type typeFromDisk = assemblyFromDisk.Modules.First().GetType("MyType"); + MethodBody body = typeFromDisk.GetMethod("Method").GetMethodBody(); + Assert.Equal(3, body.ExceptionHandlingClauses.Count); + Assert.Equal(ExceptionHandlingClauseOptions.Clause, body.ExceptionHandlingClauses[0].Flags); + Assert.Equal(ExceptionHandlingClauseOptions.Clause, body.ExceptionHandlingClauses[1].Flags); + Assert.Equal(ExceptionHandlingClauseOptions.Clause, body.ExceptionHandlingClauses[2].Flags); + Assert.Equal(exception.FullName, body.ExceptionHandlingClauses[0].CatchType.FullName); + Assert.Equal(exception.FullName, body.ExceptionHandlingClauses[1].CatchType.FullName); + Assert.Equal(exception.FullName, body.ExceptionHandlingClauses[2].CatchType.FullName); + } } } @@ -1495,8 +1573,8 @@ public void DeeperNestedTryCatchFilterFinallyBlocks() { using (TempFile file = TempFile.Create()) { - AssemblyBuilder ab = AssemblySaveTools.PopulateAssemblyBuilderTypeBuilderAndSaveMethod(out TypeBuilder tb, out MethodInfo saveMethod); - MethodBuilder method = tb.DefineMethod("Method", MethodAttributes.Public | MethodAttributes.Static, typeof(int), new[] { typeof(int), typeof(int) }); + AssemblyBuilder ab = AssemblySaveTools.PopulateAssemblyBuilderAndTypeBuilder(out TypeBuilder tb); + MethodBuilder method = tb.DefineMethod("Method", MethodAttributes.Public | MethodAttributes.Static, typeof(int), [typeof(int), typeof(int)]); Type exception = typeof(Exception); ILGenerator ilGenerator = method.GetILGenerator(); MethodInfo getMaxStackMethod = GetMaxStackMethod(); @@ -1570,20 +1648,23 @@ public void DeeperNestedTryCatchFilterFinallyBlocks() ilGenerator.Emit(OpCodes.Ldloc_0); ilGenerator.Emit(OpCodes.Ret); tb.CreateType(); - saveMethod.Invoke(ab, new object[] { file.Path }); + ab.Save(file.Path); Assert.Equal(5, getMaxStackMethod.Invoke(ilGenerator, null)); - Assembly assemblyFromDisk = AssemblySaveTools.LoadAssemblyFromPath(file.Path); - Type typeFromDisk = assemblyFromDisk.Modules.First().GetType("MyType"); - MethodBody body = typeFromDisk.GetMethod("Method").GetMethodBody(); - Assert.Equal(6, body.ExceptionHandlingClauses.Count); - Assert.Equal(ExceptionHandlingClauseOptions.Finally, body.ExceptionHandlingClauses[0].Flags); - Assert.Equal(ExceptionHandlingClauseOptions.Filter, body.ExceptionHandlingClauses[1].Flags); - Assert.Equal(ExceptionHandlingClauseOptions.Clause, body.ExceptionHandlingClauses[2].Flags); - Assert.Equal(ExceptionHandlingClauseOptions.Finally, body.ExceptionHandlingClauses[3].Flags); - Assert.Equal(ExceptionHandlingClauseOptions.Clause, body.ExceptionHandlingClauses[4].Flags); - Assert.Equal(ExceptionHandlingClauseOptions.Clause, body.ExceptionHandlingClauses[5].Flags); + using (MetadataLoadContext mlc = new MetadataLoadContext(new CoreMetadataAssemblyResolver())) + { + Assembly assemblyFromDisk = mlc.LoadFromAssemblyPath(file.Path); + Type typeFromDisk = assemblyFromDisk.Modules.First().GetType("MyType"); + MethodBody body = typeFromDisk.GetMethod("Method").GetMethodBody(); + Assert.Equal(6, body.ExceptionHandlingClauses.Count); + Assert.Equal(ExceptionHandlingClauseOptions.Finally, body.ExceptionHandlingClauses[0].Flags); + Assert.Equal(ExceptionHandlingClauseOptions.Filter, body.ExceptionHandlingClauses[1].Flags); + Assert.Equal(ExceptionHandlingClauseOptions.Clause, body.ExceptionHandlingClauses[2].Flags); + Assert.Equal(ExceptionHandlingClauseOptions.Finally, body.ExceptionHandlingClauses[3].Flags); + Assert.Equal(ExceptionHandlingClauseOptions.Clause, body.ExceptionHandlingClauses[4].Flags); + Assert.Equal(ExceptionHandlingClauseOptions.Clause, body.ExceptionHandlingClauses[5].Flags); + } } } @@ -1600,7 +1681,7 @@ public void EmitCalliBlittable() int a = 1, b = 1, result = 2; using (TempFile file = TempFile.Create()) { - AssemblyBuilder ab = AssemblySaveTools.PopulateAssemblyBuilderAndSaveMethod(new AssemblyName("EmitCalliBlittable"), out MethodInfo saveMethod); + AssemblyBuilder ab = AssemblySaveTools.PopulateAssemblyBuilder(new AssemblyName("EmitCalliBlittable")); TypeBuilder tb = ab.DefineDynamicModule("MyModule").DefineType("MyType", TypeAttributes.Public | TypeAttributes.Class); Type returnType = typeof(int); MethodBuilder methodBuilder = tb.DefineMethod("F", MethodAttributes.Public | MethodAttributes.Static, returnType, [typeof(IntPtr), typeof(int), typeof(int)]); @@ -1612,7 +1693,7 @@ public void EmitCalliBlittable() il.EmitCalli(OpCodes.Calli, CallingConvention.StdCall, returnType, [typeof(int), typeof(int)]); il.Emit(OpCodes.Ret); tb.CreateType(); - saveMethod.Invoke(ab, [file.Path]); + ab.Save(file.Path); Assembly assemblyFromDisk = Assembly.LoadFrom(file.Path); Type typeFromDisk = assemblyFromDisk.GetType("MyType"); @@ -1636,7 +1717,7 @@ public void EmitCalliManagedBlittable() int a = 1, b = 1, result = 2; using (TempFile file = TempFile.Create()) { - AssemblyBuilder ab = AssemblySaveTools.PopulateAssemblyBuilderAndSaveMethod(new AssemblyName("EmitCalliManagedBlittable"), out MethodInfo saveMethod); + AssemblyBuilder ab = AssemblySaveTools.PopulateAssemblyBuilder(new AssemblyName("EmitCalliManagedBlittable")); TypeBuilder tb = ab.DefineDynamicModule("MyModule").DefineType("MyType", TypeAttributes.Public | TypeAttributes.Class); Type returnType = typeof(int); MethodBuilder methodBuilder = tb.DefineMethod("F", MethodAttributes.Public | MethodAttributes.Static, returnType, [typeof(IntPtr), typeof(int), typeof(int)]); @@ -1650,7 +1731,7 @@ public void EmitCalliManagedBlittable() il.EmitCalli(OpCodes.Calli, CallingConventions.Standard, returnType, [typeof(int), typeof(int)], null); il.Emit(OpCodes.Ret); tb.CreateType(); - saveMethod.Invoke(ab, [file.Path]); + ab.Save(file.Path); Assembly assemblyFromDisk = Assembly.LoadFrom(file.Path); Type typeFromDisk = assemblyFromDisk.GetType("MyType"); @@ -1676,7 +1757,7 @@ public void EmitCalliNonBlittable() string input = "Test string!", result = "!gnirts tseT"; using (TempFile file = TempFile.Create()) { - AssemblyBuilder ab = AssemblySaveTools.PopulateAssemblyBuilderAndSaveMethod(new AssemblyName("EmitCalliNonBlittable"), out MethodInfo saveMethod); + AssemblyBuilder ab = AssemblySaveTools.PopulateAssemblyBuilder(new AssemblyName("EmitCalliNonBlittable")); TypeBuilder tb = ab.DefineDynamicModule("MyModule").DefineType("MyType", TypeAttributes.Public | TypeAttributes.Class); Type returnType = typeof(string); MethodBuilder methodBuilder = tb.DefineMethod("F", MethodAttributes.Public | MethodAttributes.Static, returnType, [typeof(IntPtr), typeof(string)]); @@ -1687,7 +1768,7 @@ public void EmitCalliNonBlittable() il.EmitCalli(OpCodes.Calli, CallingConvention.Cdecl, returnType, [typeof(string)]); il.Emit(OpCodes.Ret); tb.CreateType(); - saveMethod.Invoke(ab, [file.Path]); + ab.Save(file.Path); Assembly assemblyFromDisk = Assembly.LoadFrom(file.Path); Type typeFromDisk = assemblyFromDisk.GetType("MyType"); @@ -1709,7 +1790,7 @@ public void EmitCall_VarArgsMethodInIL() { using (TempFile file = TempFile.Create()) { - AssemblyBuilder ab = AssemblySaveTools.PopulateAssemblyBuilderTypeBuilderAndSaveMethod(out TypeBuilder tb, out MethodInfo saveMethod); + AssemblyBuilder ab = AssemblySaveTools.PopulateAssemblyBuilderAndTypeBuilder(out TypeBuilder tb); MethodBuilder mb1 = tb.DefineMethod("VarArgMethod", MethodAttributes.Public | MethodAttributes.Static, CallingConventions.VarArgs, null, [typeof(string)]); ILGenerator il1 = mb1.GetILGenerator(); LocalBuilder locAi = il1.DeclareLocal(typeof(ArgIterator)); @@ -1762,24 +1843,27 @@ public void EmitCall_VarArgsMethodInIL() il2.EmitCall(OpCodes.Call, mb1, [typeof(string), typeof(int)]); il2.Emit(OpCodes.Ret); Type type = tb.CreateType(); - saveMethod.Invoke(ab, [file.Path]); - - Assembly assemblyFromDisk = AssemblySaveTools.LoadAssemblyFromPath(file.Path); - Type typeFromDisk = assemblyFromDisk.Modules.First().GetType("MyType"); - MethodInfo varArgMethodFromDisk = typeFromDisk.GetMethod("VarArgMethod"); - Assert.Equal(CallingConventions.VarArgs, varArgMethodFromDisk.CallingConvention); - ParameterInfo[] parameters = varArgMethodFromDisk.GetParameters(); - Assert.Equal(1, parameters.Length); // TODO: how to get the vararg parameter? - IList locals = varArgMethodFromDisk.GetMethodBody().LocalVariables; - Assert.Equal(2, locals.Count); - Assert.Equal(typeof(ArgIterator).FullName, locals[0].LocalType.FullName); - Assert.Equal(typeof(bool).FullName, locals[1].LocalType.FullName); - - byte[] callingMethodBody = typeFromDisk.GetMethod("CallVarArgMethod").GetMethodBody().GetILAsByteArray(); - Assert.Equal(OpCodes.Ldstr.Value, callingMethodBody[0]); - Assert.Equal(OpCodes.Ldstr.Value, callingMethodBody[5]); - Assert.Equal(OpCodes.Ldc_I4.Value, callingMethodBody[10]); - Assert.Equal(OpCodes.Call.Value, callingMethodBody[15]); + ab.Save(file.Path); + + using (MetadataLoadContext mlc = new MetadataLoadContext(new CoreMetadataAssemblyResolver())) + { + Assembly assemblyFromDisk = mlc.LoadFromAssemblyPath(file.Path); + Type typeFromDisk = assemblyFromDisk.Modules.First().GetType("MyType"); + MethodInfo varArgMethodFromDisk = typeFromDisk.GetMethod("VarArgMethod"); + Assert.Equal(CallingConventions.VarArgs, varArgMethodFromDisk.CallingConvention); + ParameterInfo[] parameters = varArgMethodFromDisk.GetParameters(); + Assert.Equal(1, parameters.Length); // TODO: how to get the vararg parameter? + IList locals = varArgMethodFromDisk.GetMethodBody().LocalVariables; + Assert.Equal(2, locals.Count); + Assert.Equal(typeof(ArgIterator).FullName, locals[0].LocalType.FullName); + Assert.Equal(typeof(bool).FullName, locals[1].LocalType.FullName); + + byte[] callingMethodBody = typeFromDisk.GetMethod("CallVarArgMethod").GetMethodBody().GetILAsByteArray(); + Assert.Equal(OpCodes.Ldstr.Value, callingMethodBody[0]); + Assert.Equal(OpCodes.Ldstr.Value, callingMethodBody[5]); + Assert.Equal(OpCodes.Ldc_I4.Value, callingMethodBody[10]); + Assert.Equal(OpCodes.Call.Value, callingMethodBody[15]); + } } } @@ -1795,7 +1879,7 @@ public void Emit_CallBySignature() { using (TempFile file = TempFile.Create()) { - AssemblyBuilder ab = AssemblySaveTools.PopulateAssemblyBuilderTypeBuilderAndSaveMethod(out TypeBuilder tb, out MethodInfo saveMethod); + AssemblyBuilder ab = AssemblySaveTools.PopulateAssemblyBuilderAndTypeBuilder(out TypeBuilder tb); MethodBuilder mb1 = tb.DefineMethod("VarArgMethod", MethodAttributes.Public | MethodAttributes.Static, CallingConventions.VarArgs, null, [typeof(string)]); ILGenerator il1 = mb1.GetILGenerator(); FieldInfo maxStack = GetMaxStackDepthAndCurrentStackDepthField(out FieldInfo currentStack); @@ -1869,19 +1953,22 @@ public void Emit_CallBySignature() Assert.Equal(0, depthAdjustment.GetValue(il2)); Assert.Equal(4, getMaxStackMethod.Invoke(il2, null)); Type type = tb.CreateType(); - saveMethod.Invoke(ab, [file.Path]); - - Assembly assemblyFromDisk = AssemblySaveTools.LoadAssemblyFromPath(file.Path); - Type typeFromDisk = assemblyFromDisk.Modules.First().GetType("MyType"); - Assert.Equal(CallingConventions.VarArgs, typeFromDisk.GetMethod("VarArgMethod").CallingConvention); - - byte[] callingMethodBody = typeFromDisk.GetMethod("CallingMethod").GetMethodBody().GetILAsByteArray(); - Assert.Equal(OpCodes.Ldstr.Value, callingMethodBody[0]); - Assert.Equal(OpCodes.Ldstr.Value, callingMethodBody[5]); - Assert.Equal(OpCodes.Ldc_I4.Value, callingMethodBody[10]); - Assert.Equal(0xFE, callingMethodBody[15]); // Ldftn = 0xfe06 - Assert.Equal(0x06, callingMethodBody[16]); - Assert.Equal(OpCodes.Calli.Value, callingMethodBody[21]); + ab.Save(file.Path); + + using (MetadataLoadContext mlc = new MetadataLoadContext(new CoreMetadataAssemblyResolver())) + { + Assembly assemblyFromDisk = mlc.LoadFromAssemblyPath(file.Path); + Type typeFromDisk = assemblyFromDisk.Modules.First().GetType("MyType"); + Assert.Equal(CallingConventions.VarArgs, typeFromDisk.GetMethod("VarArgMethod").CallingConvention); + + byte[] callingMethodBody = typeFromDisk.GetMethod("CallingMethod").GetMethodBody().GetILAsByteArray(); + Assert.Equal(OpCodes.Ldstr.Value, callingMethodBody[0]); + Assert.Equal(OpCodes.Ldstr.Value, callingMethodBody[5]); + Assert.Equal(OpCodes.Ldc_I4.Value, callingMethodBody[10]); + Assert.Equal(0xFE, callingMethodBody[15]); // Ldftn = 0xfe06 + Assert.Equal(0x06, callingMethodBody[16]); + Assert.Equal(OpCodes.Calli.Value, callingMethodBody[21]); + } } } @@ -1902,7 +1989,7 @@ public void MaxStackOverflowTest() /// static void GetCode(int num) { - AssemblySaveTools.PopulateAssemblyBuilderTypeBuilderAndSaveMethod(out TypeBuilder type, out MethodInfo _); + AssemblySaveTools.PopulateAssemblyBuilderAndTypeBuilder(out TypeBuilder type); MethodBuilder method = type.DefineMethod("meth1", MethodAttributes.Public | MethodAttributes.Static, typeof(int), Type.EmptyTypes); var ilg = method.GetILGenerator(); @@ -1948,7 +2035,7 @@ public void MaxStackNonEmptyForward() static void GetCode(int num) { - AssemblySaveTools.PopulateAssemblyBuilderTypeBuilderAndSaveMethod(out TypeBuilder type, out MethodInfo _); + AssemblySaveTools.PopulateAssemblyBuilderAndTypeBuilder(out TypeBuilder type); MethodBuilder method = type.DefineMethod("meth1", MethodAttributes.Public | MethodAttributes.Static, typeof(int), null); var ilg = method.GetILGenerator(); @@ -1997,7 +2084,7 @@ public void MaxStackNonEmptyBackward() static void GetCode(int num) { - AssemblySaveTools.PopulateAssemblyBuilderTypeBuilderAndSaveMethod(out TypeBuilder type, out MethodInfo _); + AssemblySaveTools.PopulateAssemblyBuilderAndTypeBuilder(out TypeBuilder type); MethodBuilder method = type.DefineMethod("meth1", MethodAttributes.Public | MethodAttributes.Static, typeof(int), Type.EmptyTypes); var ilg = method.GetILGenerator(); @@ -2051,8 +2138,8 @@ public void AmbiguousDepth() static void GetCode() { - AssemblySaveTools.PopulateAssemblyBuilderTypeBuilderAndSaveMethod(out TypeBuilder type, out MethodInfo _); - MethodBuilder method = type.DefineMethod("meth1", MethodAttributes.Public | MethodAttributes.Static, typeof(int), new[] { typeof(bool) }); + AssemblySaveTools.PopulateAssemblyBuilderAndTypeBuilder(out TypeBuilder type); + MethodBuilder method = type.DefineMethod("meth1", MethodAttributes.Public | MethodAttributes.Static, typeof(int), [typeof(bool)]); var ilg = method.GetILGenerator(); // The label is targeted with stack depth zero. @@ -2082,7 +2169,7 @@ public void UnreachableDepth() static void GetCode() { - AssemblySaveTools.PopulateAssemblyBuilderTypeBuilderAndSaveMethod(out TypeBuilder type, out MethodInfo _); + AssemblySaveTools.PopulateAssemblyBuilderAndTypeBuilder(out TypeBuilder type); MethodBuilder method = type.DefineMethod("meth1", MethodAttributes.Public | MethodAttributes.Static, typeof(int), Type.EmptyTypes); var ilg = method.GetILGenerator(); @@ -2113,7 +2200,7 @@ public void SimpleForLoopTest() { using (TempFile file = TempFile.Create()) { - AssemblyBuilder ab = AssemblySaveTools.PopulateAssemblyBuilderTypeBuilderAndSaveMethod(out TypeBuilder tb, out MethodInfo saveMethod); + AssemblyBuilder ab = AssemblySaveTools.PopulateAssemblyBuilderAndTypeBuilder(out TypeBuilder tb); MethodBuilder mb2 = tb.DefineMethod("SumMethod", MethodAttributes.Public | MethodAttributes.Static, typeof(int), [typeof(int)]); ILGenerator il = mb2.GetILGenerator(); LocalBuilder sum = il.DeclareLocal(typeof(int)); @@ -2141,7 +2228,7 @@ public void SimpleForLoopTest() il.Emit(OpCodes.Ldloc_0); il.Emit(OpCodes.Ret); tb.CreateType(); - saveMethod.Invoke(ab, [file.Path]); + ab.Save(file.Path); MethodInfo getMaxStackMethod = GetMaxStackMethod(); Assert.Equal(2, getMaxStackMethod.Invoke(il, null)); @@ -2162,7 +2249,7 @@ public void RecursiveSumTest() { using (TempFile file = TempFile.Create()) { - AssemblyBuilder ab = AssemblySaveTools.PopulateAssemblyBuilderAndSaveMethod(new AssemblyName("RecursiveSumTest"), out MethodInfo saveMethod); + AssemblyBuilder ab = AssemblySaveTools.PopulateAssemblyBuilder(new AssemblyName("RecursiveSumTest")); TypeBuilder tb = ab.DefineDynamicModule("MyModule").DefineType("MyType", TypeAttributes.Public | TypeAttributes.Class); MethodBuilder mb2 = tb.DefineMethod("RecursiveMethod", MethodAttributes.Public | MethodAttributes.Static, typeof(int), [typeof(int)]); ILGenerator il = mb2.GetILGenerator(); @@ -2181,7 +2268,7 @@ public void RecursiveSumTest() il.Emit(OpCodes.Ldc_I4_0); il.Emit(OpCodes.Ret); tb.CreateType(); - saveMethod.Invoke(ab, [file.Path]); + ab.Save(file.Path); MethodInfo getMaxStackMethod = GetMaxStackMethod(); Assert.Equal(3, getMaxStackMethod.Invoke(il, null)); @@ -2203,7 +2290,7 @@ public void CallOpenGenericMembersFromConstructedGenericType() { using (TempFile file = TempFile.Create()) { - AssemblyBuilder ab = AssemblySaveTools.PopulateAssemblyBuilderTypeBuilderAndSaveMethod(out TypeBuilder type, out MethodInfo saveMethod); + AssemblyBuilder ab = AssemblySaveTools.PopulateAssemblyBuilderAndTypeBuilder(out TypeBuilder type); MethodBuilder method = type.DefineMethod("M1", MethodAttributes.Public, typeof(string), null); ILGenerator ilGenerator = method.GetILGenerator(); @@ -2223,7 +2310,7 @@ public void CallOpenGenericMembersFromConstructedGenericType() ilGenerator.Emit(OpCodes.Ret); type.CreateType(); - saveMethod.Invoke(ab, [file.Path]); + ab.Save(file.Path); Type typeFromDisk = Assembly.LoadFile(file.Path).GetType("MyType"); string result = (string)typeFromDisk.GetMethod("M1").Invoke(Activator.CreateInstance(typeFromDisk), null); diff --git a/src/libraries/System.Reflection.Emit/tests/PersistableAssemblyBuilder/AssemblySaveMethodBuilderTests.cs b/src/libraries/System.Reflection.Emit/tests/PersistableAssemblyBuilder/AssemblySaveMethodBuilderTests.cs index 5d1b92e0cf52d4..787b121fc80433 100644 --- a/src/libraries/System.Reflection.Emit/tests/PersistableAssemblyBuilder/AssemblySaveMethodBuilderTests.cs +++ b/src/libraries/System.Reflection.Emit/tests/PersistableAssemblyBuilder/AssemblySaveMethodBuilderTests.cs @@ -15,7 +15,7 @@ public void DefineMethodOverride_InterfaceMethod() { using (TempFile file = TempFile.Create()) { - AssemblyBuilder ab = AssemblySaveTools.PopulateAssemblyBuilderTypeBuilderAndSaveMethod(out TypeBuilder type, out MethodInfo saveMethod); + AssemblyBuilder ab = AssemblySaveTools.PopulateAssemblyBuilderAndTypeBuilder(out TypeBuilder type); MethodBuilder method = type.DefineMethod("MImpl", MethodAttributes.Public | MethodAttributes.Virtual, typeof(int), null); ILGenerator ilGenerator = method.GetILGenerator(); ilGenerator.Emit(OpCodes.Ldc_I4, 2); @@ -24,7 +24,7 @@ public void DefineMethodOverride_InterfaceMethod() MethodInfo declaration = typeof(DefineMethodOverrideInterface).GetMethod("M"); type.DefineMethodOverride(method, declaration); type.CreateType(); - saveMethod.Invoke(ab, [file.Path]); + ab.Save(file.Path); InterfaceMapping im = type.GetInterfaceMap(typeof(DefineMethodOverrideInterface)); Assert.Equal(type, im.TargetType); @@ -33,9 +33,12 @@ public void DefineMethodOverride_InterfaceMethod() Assert.Equal(declaration, im.InterfaceMethods[0]); Assert.Equal(method, im.TargetMethods[0]); - Type typeFromDisk = AssemblySaveTools.LoadAssemblyFromPath(file.Path).GetType("MyType"); - MethodInfo methodFromDisk = typeFromDisk.GetMethod("MImpl"); - Assert.True(methodFromDisk.IsVirtual); + using (MetadataLoadContext mlc = new MetadataLoadContext(new CoreMetadataAssemblyResolver())) + { + Type typeFromDisk = mlc.LoadFromAssemblyPath(file.Path).GetType("MyType"); + MethodInfo methodFromDisk = typeFromDisk.GetMethod("MImpl"); + Assert.True(methodFromDisk.IsVirtual); + } } } @@ -44,7 +47,7 @@ public void DefineMethodOverride_BaseTypeImplementation() { using (TempFile file = TempFile.Create()) { - AssemblyBuilder ab = AssemblySaveTools.PopulateAssemblyBuilderTypeBuilderAndSaveMethod(out TypeBuilder type, out MethodInfo saveMethod); + AssemblyBuilder ab = AssemblySaveTools.PopulateAssemblyBuilderAndTypeBuilder(out TypeBuilder type); type.SetParent(typeof(DefineMethodOverrideClass)); MethodBuilder method = type.DefineMethod("M2", MethodAttributes.Public | MethodAttributes.Virtual, typeof(int), null); ILGenerator ilGenerator = method.GetILGenerator(); @@ -53,10 +56,13 @@ public void DefineMethodOverride_BaseTypeImplementation() MethodInfo declaration = typeof(DefineMethodOverrideClass).GetMethod("M"); type.DefineMethodOverride(method, declaration); Type createdType = type.CreateType(); - saveMethod.Invoke(ab, [file.Path]); + ab.Save(file.Path); - Type typeFromDisk = AssemblySaveTools.LoadAssemblyFromPath(file.Path).GetType("MyType"); - Assert.True(typeFromDisk.GetMethod("M2").IsVirtual); + using (MetadataLoadContext mlc = new MetadataLoadContext(new CoreMetadataAssemblyResolver())) + { + Type typeFromDisk = mlc.LoadFromAssemblyPath(file.Path).GetType("MyType"); + Assert.True(typeFromDisk.GetMethod("M2").IsVirtual); + } } } @@ -65,7 +71,7 @@ public void DefineMethodOverride_GenericInterface_Succeeds() { using (TempFile file = TempFile.Create()) { - AssemblyBuilder ab = AssemblySaveTools.PopulateAssemblyBuilderTypeBuilderAndSaveMethod(out TypeBuilder type, out MethodInfo saveMethod); + AssemblyBuilder ab = AssemblySaveTools.PopulateAssemblyBuilderAndTypeBuilder(out TypeBuilder type); type.AddInterfaceImplementation(typeof(GenericInterface)); MethodBuilder method = type.DefineMethod("Method", MethodAttributes.Public | MethodAttributes.Virtual, typeof(string), Type.EmptyTypes); ILGenerator ilGenerator = method.GetILGenerator(); @@ -73,25 +79,28 @@ public void DefineMethodOverride_GenericInterface_Succeeds() ilGenerator.Emit(OpCodes.Ret); type.DefineMethodOverride(method, typeof(GenericInterface).GetMethod("Method")); Type createdType = type.CreateType(); - saveMethod.Invoke(ab, [file.Path]); - - Type typeFromDisk = AssemblySaveTools.LoadAssemblyFromPath(file.Path).GetType("MyType"); - MethodInfo methodFromDisk = typeFromDisk.GetMethod("Method"); - Assert.True(methodFromDisk.IsVirtual); - - InterfaceMapping im = type.GetInterfaceMap(typeof(GenericInterface)); - Assert.Equal(type, im.TargetType); - Assert.Equal(typeof(GenericInterface), im.InterfaceType); - Assert.Equal(1, im.InterfaceMethods.Length); - Assert.Equal(typeof(GenericInterface).GetMethod("Method"), im.InterfaceMethods[0]); - Assert.Equal(method, im.TargetMethods[0]); + ab.Save(file.Path); + + using (MetadataLoadContext mlc = new MetadataLoadContext(new CoreMetadataAssemblyResolver())) + { + Type typeFromDisk = mlc.LoadFromAssemblyPath(file.Path).GetType("MyType"); + MethodInfo methodFromDisk = typeFromDisk.GetMethod("Method"); + Assert.True(methodFromDisk.IsVirtual); + + InterfaceMapping im = type.GetInterfaceMap(typeof(GenericInterface)); + Assert.Equal(type, im.TargetType); + Assert.Equal(typeof(GenericInterface), im.InterfaceType); + Assert.Equal(1, im.InterfaceMethods.Length); + Assert.Equal(typeof(GenericInterface).GetMethod("Method"), im.InterfaceMethods[0]); + Assert.Equal(method, im.TargetMethods[0]); + } } } [Fact] public void DefineMethodOverride_NullMethodInfoBody_ThrowsArgumentNullException() { - AssemblySaveTools.PopulateAssemblyBuilderTypeBuilderAndSaveMethod(out TypeBuilder type, out MethodInfo _); + AssemblySaveTools.PopulateAssemblyBuilderAndTypeBuilder(out TypeBuilder type); MethodInfo method = typeof(DefineMethodOverrideClass).GetMethod("M"); MethodInfo imethod = typeof(DefineMethodOverrideInterface).GetMethod("M"); @@ -102,7 +111,7 @@ public void DefineMethodOverride_NullMethodInfoBody_ThrowsArgumentNullException( [Fact] public void DefineMethodOverride_MethodNotInClass_ThrowsArgumentException() { - AssemblySaveTools.PopulateAssemblyBuilderTypeBuilderAndSaveMethod(out TypeBuilder type, out MethodInfo _); + AssemblySaveTools.PopulateAssemblyBuilderAndTypeBuilder(out TypeBuilder type); MethodInfo body = typeof(DefineMethodOverrideInterface).GetMethod("M"); MethodInfo declaration = typeof(DefineMethodOverrideClass).GetMethod("M"); @@ -112,7 +121,7 @@ public void DefineMethodOverride_MethodNotInClass_ThrowsArgumentException() [Fact] public void DefineMethodOverride_TypeCreated_ThrowsInvalidOperationException() { - AssemblySaveTools.PopulateAssemblyBuilderTypeBuilderAndSaveMethod(out TypeBuilder type, out MethodInfo _); + AssemblySaveTools.PopulateAssemblyBuilderAndTypeBuilder(out TypeBuilder type); MethodBuilder method = type.DefineMethod("M", MethodAttributes.Public | MethodAttributes.Virtual, typeof(int), null); method.GetILGenerator().Emit(OpCodes.Ret); type.AddInterfaceImplementation(typeof(DefineMethodOverrideInterface)); @@ -126,7 +135,7 @@ public void DefineMethodOverride_TypeCreated_ThrowsInvalidOperationException() [Fact] public void DefineMethodOverride_MethodNotVirtual_ThrowsArgumentException() { - AssemblySaveTools.PopulateAssemblyBuilderTypeBuilderAndSaveMethod(out TypeBuilder type, out MethodInfo _); + AssemblySaveTools.PopulateAssemblyBuilderAndTypeBuilder(out TypeBuilder type); MethodBuilder method = type.DefineMethod("M", MethodAttributes.Public, typeof(int), null); ILGenerator ilGenerator = method.GetILGenerator(); ilGenerator.Emit(OpCodes.Ldc_I4, 2); @@ -141,7 +150,7 @@ public void DefineMethodOverride_MethodNotVirtual_ThrowsArgumentException() [Fact] public void DefineMethodOverride_TypeDoesNotImplementOrInheritMethod_ThrowsArgumentException() { - AssemblySaveTools.PopulateAssemblyBuilderTypeBuilderAndSaveMethod(out TypeBuilder type, out MethodInfo _); + AssemblySaveTools.PopulateAssemblyBuilderAndTypeBuilder(out TypeBuilder type); MethodBuilder method = type.DefineMethod("M", MethodAttributes.Public | MethodAttributes.Virtual, typeof(int), null); method.GetILGenerator().Emit(OpCodes.Ret); MethodInfo interfaceMethod = typeof(DefineMethodOverrideInterface).GetMethod("M"); @@ -158,7 +167,7 @@ public void DefineMethodOverride_TypeDoesNotImplementOrInheritMethod_ThrowsArgum [Fact] public void DefineMethodOverride_CalledAgainWithSameDeclaration_ThrowsArgumentException() { - AssemblySaveTools.PopulateAssemblyBuilderTypeBuilderAndSaveMethod(out TypeBuilder type, out MethodInfo _); + AssemblySaveTools.PopulateAssemblyBuilderAndTypeBuilder(out TypeBuilder type); MethodBuilder method1 = type.DefineMethod("M", MethodAttributes.Public | MethodAttributes.Virtual, typeof(int), null); ILGenerator ilGenerator1 = method1.GetILGenerator(); ilGenerator1.Emit(OpCodes.Ldc_I4, 1); @@ -185,7 +194,7 @@ public void DefineMethodOverride_CalledAgainWithSameDeclaration_ThrowsArgumentEx [InlineData(typeof(string), new Type[] { typeof(string), typeof(int) })] public void DefineMethodOverride_BodyAndDeclarationHaveDifferentSignatures_ThrowsArgumentException(Type returnType, Type[] parameterTypes) { - AssemblySaveTools.PopulateAssemblyBuilderTypeBuilderAndSaveMethod(out TypeBuilder type, out MethodInfo _); + AssemblySaveTools.PopulateAssemblyBuilderAndTypeBuilder(out TypeBuilder type); MethodBuilder method = type.DefineMethod("M", MethodAttributes.Public | MethodAttributes.Virtual, returnType, parameterTypes); method.GetILGenerator().Emit(OpCodes.Ret); type.AddInterfaceImplementation(typeof(InterfaceWithMethod)); @@ -208,7 +217,7 @@ public interface InterfaceWithMethod [Fact] public void DefineMethodOverride_StaticVirtualInterfaceMethodWorks() { - AssemblyBuilder ab = AssemblySaveTools.PopulateAssemblyBuilderTypeBuilderAndSaveMethod(out TypeBuilder type, out MethodInfo _); + AssemblyBuilder ab = AssemblySaveTools.PopulateAssemblyBuilderAndTypeBuilder(out TypeBuilder type); ModuleBuilder module = ab.GetDynamicModule("MyModule"); TypeBuilder interfaceType = module.DefineType("InterfaceType", TypeAttributes.Public | TypeAttributes.Interface | TypeAttributes.Abstract, parent: null); @@ -238,7 +247,7 @@ public abstract class Impl : InterfaceWithMethod [Fact] public void GetInterfaceMap_WithImplicitOverride_DefineMethodOverride() { - AssemblyBuilder ab = AssemblySaveTools.PopulateAssemblyBuilderTypeBuilderAndSaveMethod(out TypeBuilder type, out MethodInfo _); + AssemblyBuilder ab = AssemblySaveTools.PopulateAssemblyBuilderAndTypeBuilder(out TypeBuilder type); ModuleBuilder module = ab.GetDynamicModule("MyModule"); TypeBuilder interfaceType = module.DefineType("InterfaceType", TypeAttributes.Public | TypeAttributes.Interface | TypeAttributes.Abstract, parent: null); @@ -292,7 +301,7 @@ public void GetInterfaceMap_WithImplicitOverride_DefineMethodOverride() [Fact] public void GetInterfaceMap_Validations() { - AssemblySaveTools.PopulateAssemblyBuilderTypeBuilderAndSaveMethod(out TypeBuilder type, out MethodInfo _); + AssemblySaveTools.PopulateAssemblyBuilderAndTypeBuilder(out TypeBuilder type); type.AddInterfaceImplementation(typeof(DefineMethodOverrideInterface)); Assert.Throws(() => type.GetInterfaceMap(typeof(Impl))); // concreteTypeWithAbstractMethod not created @@ -318,7 +327,7 @@ public abstract class PartialImplementation : InterfaceDerivedFromOtherInterface [Fact] public void CreateType_ValidateAllAbstractMethodsAreImplemented() { - AssemblyBuilder ab = AssemblySaveTools.PopulateAssemblyBuilderTypeBuilderAndSaveMethod(out TypeBuilder typeNotImplementedIfaceMethod, out MethodInfo _); + AssemblyBuilder ab = AssemblySaveTools.PopulateAssemblyBuilderAndTypeBuilder(out TypeBuilder typeNotImplementedIfaceMethod); typeNotImplementedIfaceMethod.AddInterfaceImplementation(typeof(DefineMethodOverrideInterface)); ModuleBuilder module = ab.GetDynamicModule("MyModule"); TypeBuilder partiallyImplementedType = module.DefineType("Type2", TypeAttributes.Public); @@ -339,7 +348,7 @@ public void CreateType_ValidateAllAbstractMethodsAreImplemented() [Fact] public void CreateType_ValidateMethods() { - AssemblyBuilder ab = AssemblySaveTools.PopulateAssemblyBuilderTypeBuilderAndSaveMethod(out TypeBuilder concreteTypeWithAbstractMethod, out MethodInfo _); + AssemblyBuilder ab = AssemblySaveTools.PopulateAssemblyBuilderAndTypeBuilder(out TypeBuilder concreteTypeWithAbstractMethod); concreteTypeWithAbstractMethod.DefineMethod("AbstractMethod", MethodAttributes.Public | MethodAttributes.Abstract); Assert.Throws(() => concreteTypeWithAbstractMethod.CreateType()); // Type must be declared abstract if any of its methods are abstract. @@ -366,7 +375,7 @@ public void CreateType_ValidateMethods() [Fact] public void GetMethodsGetMethodImpl_Tests() { - AssemblySaveTools.PopulateAssemblyBuilderTypeBuilderAndSaveMethod(out TypeBuilder type, out MethodInfo saveMethod); + AssemblySaveTools.PopulateAssemblyBuilderAndTypeBuilder(out TypeBuilder type); MethodBuilder voidPublicMethod = type.DefineMethod("VoidMethod", MethodAttributes.Public, typeof(void), [typeof(int)]); MethodBuilder voidAssemblyStaticMethod = type.DefineMethod("VoidMethod", MethodAttributes.Assembly | MethodAttributes.Static, typeof(void), Type.EmptyTypes); MethodBuilder voidFamilyOrAssemblyMethod = type.DefineMethod("VoidMethod", MethodAttributes.FamORAssem, typeof(void), Type.EmptyTypes); diff --git a/src/libraries/System.Reflection.Emit/tests/PersistableAssemblyBuilder/AssemblySavePropertyBuilderTests.cs b/src/libraries/System.Reflection.Emit/tests/PersistableAssemblyBuilder/AssemblySavePropertyBuilderTests.cs index e478827125e7c7..c18eb017c14284 100644 --- a/src/libraries/System.Reflection.Emit/tests/PersistableAssemblyBuilder/AssemblySavePropertyBuilderTests.cs +++ b/src/libraries/System.Reflection.Emit/tests/PersistableAssemblyBuilder/AssemblySavePropertyBuilderTests.cs @@ -18,7 +18,7 @@ public void SetPropertyAccessorsAndOtherValues() { using (TempFile file = TempFile.Create()) { - AssemblyBuilder ab = AssemblySaveTools.PopulateAssemblyBuilderTypeBuilderAndSaveMethod(out TypeBuilder type, out MethodInfo saveMethod); + AssemblyBuilder ab = AssemblySaveTools.PopulateAssemblyBuilderAndTypeBuilder(out TypeBuilder type); FieldBuilder field = type.DefineField("TestField", typeof(int), FieldAttributes.Private); PropertyBuilder property = type.DefineProperty("TestProperty", PropertyAttributes.SpecialName | PropertyAttributes.HasDefault, typeof(int), null); MethodBuilder getMethod = type.DefineMethod("GetMethod", MethodAttributes.Public | MethodAttributes.HideBySig, typeof(int), null); @@ -44,29 +44,32 @@ public void SetPropertyAccessorsAndOtherValues() otherILGenerator.Emit(OpCodes.Ret); property.AddOtherMethod(otherMethod); type.CreateType(); - saveMethod.Invoke(ab, new [] { file.Path }); - - Assembly assemblyFromDisk = AssemblySaveTools.LoadAssemblyFromPath(file.Path); - Type typeFromDisk = assemblyFromDisk.Modules.First().GetType("MyType"); - PropertyInfo propertyFromDisk = typeFromDisk.GetProperty("TestProperty", BindingFlags.Public | BindingFlags.NonPublic | BindingFlags.Instance); - MethodInfo getMethodFromFile = propertyFromDisk.GetGetMethod(true); - MethodInfo setMethodFromFile = propertyFromDisk.GetSetMethod(true); - Assert.Equal(getMethod.Name, getMethodFromFile.Name); - Assert.Equal(setMethod.Name, setMethodFromFile.Name); - // Not sure how other methods should have loaded/tested - // 'propertyFromDisk.GetAccessors(true)' did not return other method - Assert.NotNull(typeFromDisk.GetMethod("OtherMethod", BindingFlags.NonPublic | BindingFlags.Instance)); - Assert.True(property.CanRead); - Assert.True(property.CanWrite); - Assert.Equal(property.CanRead, propertyFromDisk.CanRead); - Assert.Equal(property.CanWrite, propertyFromDisk.CanWrite); - Assert.Equal(property.Attributes, propertyFromDisk.Attributes); - Assert.Equal(property.DeclaringType.FullName, propertyFromDisk.DeclaringType.FullName); - IList caData = propertyFromDisk.GetCustomAttributesData(); - Assert.Equal(1, caData.Count); - Assert.Equal(typeof(IntPropertyAttribute).FullName, caData[0].AttributeType.FullName); - Assert.Equal(1, caData[0].ConstructorArguments.Count); - Assert.Equal(9, caData[0].ConstructorArguments[0].Value); + ab.Save(file.Path); + + using (MetadataLoadContext mlc = new MetadataLoadContext(new CoreMetadataAssemblyResolver())) + { + Assembly assemblyFromDisk = mlc.LoadFromAssemblyPath(file.Path); + Type typeFromDisk = assemblyFromDisk.Modules.First().GetType("MyType"); + PropertyInfo propertyFromDisk = typeFromDisk.GetProperty("TestProperty", BindingFlags.Public | BindingFlags.NonPublic | BindingFlags.Instance); + MethodInfo getMethodFromFile = propertyFromDisk.GetGetMethod(true); + MethodInfo setMethodFromFile = propertyFromDisk.GetSetMethod(true); + Assert.Equal(getMethod.Name, getMethodFromFile.Name); + Assert.Equal(setMethod.Name, setMethodFromFile.Name); + // Not sure how other methods should have loaded/tested + // 'propertyFromDisk.GetAccessors(true)' did not return other method + Assert.NotNull(typeFromDisk.GetMethod("OtherMethod", BindingFlags.NonPublic | BindingFlags.Instance)); + Assert.True(property.CanRead); + Assert.True(property.CanWrite); + Assert.Equal(property.CanRead, propertyFromDisk.CanRead); + Assert.Equal(property.CanWrite, propertyFromDisk.CanWrite); + Assert.Equal(property.Attributes, propertyFromDisk.Attributes); + Assert.Equal(property.DeclaringType.FullName, propertyFromDisk.DeclaringType.FullName); + IList caData = propertyFromDisk.GetCustomAttributesData(); + Assert.Equal(1, caData.Count); + Assert.Equal(typeof(IntPropertyAttribute).FullName, caData[0].AttributeType.FullName); + Assert.Equal(1, caData[0].ConstructorArguments.Count); + Assert.Equal(9, caData[0].ConstructorArguments[0].Value); + } } } @@ -81,7 +84,7 @@ public void SetVariousCustomAttributes_ForProperty() PropertyInfo prop = typeof(CustomAttributeBuilder).GetProperty("Data", BindingFlags.NonPublic | BindingFlags.Instance); byte[] binaryData = (byte[])prop.GetValue(customAttrBuilder, null); - AssemblyBuilder ab = AssemblySaveTools.PopulateAssemblyBuilderTypeBuilderAndSaveMethod(out TypeBuilder type, out MethodInfo saveMethod); + AssemblyBuilder ab = AssemblySaveTools.PopulateAssemblyBuilderAndTypeBuilder(out TypeBuilder type); PropertyBuilder property = type.DefineProperty("TestProperty", PropertyAttributes.HasDefault, typeof(int), null); property.SetCustomAttribute(con, binaryData); property.SetCustomAttribute(new CustomAttributeBuilder(typeof(SpecialNameAttribute).GetConstructor(Type.EmptyTypes), [])); @@ -93,30 +96,33 @@ public void SetVariousCustomAttributes_ForProperty() methodILGenerator.Emit(OpCodes.Ret); property.SetGetMethod(method); type.CreateType(); - saveMethod.Invoke(ab, [file.Path]); - - Assembly assemblyFromDisk = AssemblySaveTools.LoadAssemblyFromPath(file.Path); - Type typeFromDisk = assemblyFromDisk.Modules.First().GetType("MyType"); - PropertyInfo propertyFromDisk = typeFromDisk.GetProperty("TestProperty", BindingFlags.Public | BindingFlags.Instance | BindingFlags.NonPublic); - Assert.True(propertyFromDisk.Attributes.HasFlag(PropertyAttributes.SpecialName)); - IList attributes = propertyFromDisk.GetCustomAttributesData(); - Assert.Equal(2, attributes.Count); - if (typeof(MaybeNullAttribute).FullName == attributes[0].AttributeType.FullName) - { - Assert.Equal(0, attributes[0].ConstructorArguments.Count); - Assert.Equal(1, attributes[1].ConstructorArguments.Count); - Assert.Equal(typeof(IntPropertyAttribute).FullName, attributes[1].AttributeType.FullName); - Assert.Equal(expectedValue, attributes[1].ConstructorArguments[0].Value); - } - else + ab.Save(file.Path); + + using (MetadataLoadContext mlc = new MetadataLoadContext(new CoreMetadataAssemblyResolver())) { - Assert.Equal(0, attributes[1].ConstructorArguments.Count); - Assert.Equal(1, attributes[0].ConstructorArguments.Count); - Assert.Equal(typeof(IntPropertyAttribute).FullName, attributes[0].AttributeType.FullName); - Assert.Equal(expectedValue, attributes[0].ConstructorArguments[0].Value); + Assembly assemblyFromDisk = mlc.LoadFromAssemblyPath(file.Path); + Type typeFromDisk = assemblyFromDisk.Modules.First().GetType("MyType"); + PropertyInfo propertyFromDisk = typeFromDisk.GetProperty("TestProperty", BindingFlags.Public | BindingFlags.Instance | BindingFlags.NonPublic); + Assert.True(propertyFromDisk.Attributes.HasFlag(PropertyAttributes.SpecialName)); + IList attributes = propertyFromDisk.GetCustomAttributesData(); + Assert.Equal(2, attributes.Count); + if (typeof(MaybeNullAttribute).FullName == attributes[0].AttributeType.FullName) + { + Assert.Equal(0, attributes[0].ConstructorArguments.Count); + Assert.Equal(1, attributes[1].ConstructorArguments.Count); + Assert.Equal(typeof(IntPropertyAttribute).FullName, attributes[1].AttributeType.FullName); + Assert.Equal(expectedValue, attributes[1].ConstructorArguments[0].Value); + } + else + { + Assert.Equal(0, attributes[1].ConstructorArguments.Count); + Assert.Equal(1, attributes[0].ConstructorArguments.Count); + Assert.Equal(typeof(IntPropertyAttribute).FullName, attributes[0].AttributeType.FullName); + Assert.Equal(expectedValue, attributes[0].ConstructorArguments[0].Value); + } + Assert.Empty(attributes[0].NamedArguments); + Assert.Empty(attributes[1].NamedArguments); } - Assert.Empty(attributes[0].NamedArguments); - Assert.Empty(attributes[1].NamedArguments); } } @@ -149,7 +155,7 @@ public static IEnumerable SetConstant_TestData() [MemberData(nameof(SetConstant_TestData))] public void SetConstantVariousValues(Type returnType, object defaultValue) { - AssemblySaveTools.PopulateAssemblyBuilderTypeBuilderAndSaveMethod(out TypeBuilder type, out MethodInfo _); + AssemblySaveTools.PopulateAssemblyBuilderAndTypeBuilder(out TypeBuilder type); PropertyBuilder property = type.DefineProperty("TestProperty", PropertyAttributes.HasDefault, returnType, null); property.SetConstant(defaultValue); @@ -160,7 +166,7 @@ public void SetConstantVariousValues(Type returnType, object defaultValue) [Fact] public void SetCustomAttribute_ConstructorInfo_ByteArray_NullConstructorInfo_ThrowsArgumentNullException() { - AssemblySaveTools.PopulateAssemblyBuilderTypeBuilderAndSaveMethod(out TypeBuilder type, out MethodInfo _); + AssemblySaveTools.PopulateAssemblyBuilderAndTypeBuilder(out TypeBuilder type); PropertyBuilder property = type.DefineProperty("TestProperty", PropertyAttributes.HasDefault, typeof(int), null); AssertExtensions.Throws("con", () => property.SetCustomAttribute(null, new byte[6])); @@ -169,7 +175,7 @@ public void SetCustomAttribute_ConstructorInfo_ByteArray_NullConstructorInfo_Thr [Fact] public void Set_NullValue_ThrowsArgumentNullException() { - AssemblySaveTools.PopulateAssemblyBuilderTypeBuilderAndSaveMethod(out TypeBuilder type, out MethodInfo _); + AssemblySaveTools.PopulateAssemblyBuilderAndTypeBuilder(out TypeBuilder type); PropertyBuilder property = type.DefineProperty("TestProperty", PropertyAttributes.None, typeof(int), null); AssertExtensions.Throws("mdBuilder", () => property.SetGetMethod(null)); @@ -181,7 +187,7 @@ public void Set_NullValue_ThrowsArgumentNullException() [Fact] public void Set_WhenTypeAlreadyCreated_ThrowsInvalidOperationException() { - AssemblySaveTools.PopulateAssemblyBuilderTypeBuilderAndSaveMethod(out TypeBuilder type, out MethodInfo _); + AssemblySaveTools.PopulateAssemblyBuilderAndTypeBuilder(out TypeBuilder type); FieldBuilder field = type.DefineField("TestField", typeof(int), FieldAttributes.Private); PropertyBuilder property = type.DefineProperty("TestProperty", PropertyAttributes.HasDefault, typeof(int), null); @@ -202,7 +208,7 @@ public void Set_WhenTypeAlreadyCreated_ThrowsInvalidOperationException() [Fact] public void SetConstant_ValidationThrows() { - AssemblySaveTools.PopulateAssemblyBuilderTypeBuilderAndSaveMethod(out TypeBuilder type, out MethodInfo _); + AssemblySaveTools.PopulateAssemblyBuilderAndTypeBuilder(out TypeBuilder type); FieldBuilder field = type.DefineField("TestField", typeof(int), FieldAttributes.Private); PropertyBuilder property = type.DefineProperty("TestProperty", PropertyAttributes.HasDefault, typeof(int), null); diff --git a/src/libraries/System.Reflection.Emit/tests/PersistableAssemblyBuilder/AssemblySaveTools.cs b/src/libraries/System.Reflection.Emit/tests/PersistableAssemblyBuilder/AssemblySaveTools.cs index 69ec92d4b97a51..46beedf8cbb93b 100644 --- a/src/libraries/System.Reflection.Emit/tests/PersistableAssemblyBuilder/AssemblySaveTools.cs +++ b/src/libraries/System.Reflection.Emit/tests/PersistableAssemblyBuilder/AssemblySaveTools.cs @@ -17,13 +17,12 @@ internal static class AssemblySaveTools internal static void WriteAssemblyToDisk(AssemblyName assemblyName, Type[] types, string fileLocation) { - AssemblyBuilder assemblyBuilder = PopulateAssemblyBuilderAndSaveMethod( - assemblyName, null, typeof(string), out MethodInfo saveMethod); + AssemblyBuilder assemblyBuilder = PopulateAssemblyBuilder(assemblyName); ModuleBuilder mb = assemblyBuilder.DefineDynamicModule(assemblyName.Name); PopulateMembersForModule(mb, types); - saveMethod.Invoke(assemblyBuilder, new object[] { fileLocation }); + assemblyBuilder.Save(fileLocation); } private static void PopulateMembersForModule(ModuleBuilder mb, Type[] types) @@ -54,41 +53,23 @@ private static void PopulateMembersForModule(ModuleBuilder mb, Type[] types) internal static void WriteAssemblyToStream(AssemblyName assemblyName, Type[] types, Stream stream) { - AssemblyBuilder assemblyBuilder = PopulateAssemblyBuilderAndSaveMethod( - assemblyName, null, typeof(Stream), out MethodInfo saveMethod); + AssemblyBuilder assemblyBuilder = PopulateAssemblyBuilder(assemblyName); ModuleBuilder mb = assemblyBuilder.DefineDynamicModule(assemblyName.Name); PopulateMembersForModule(mb, types); - saveMethod.Invoke(assemblyBuilder, new object[] { stream }); + assemblyBuilder.Save(stream); } - internal static AssemblyBuilder PopulateAssemblyBuilderTypeBuilderAndSaveMethod(out TypeBuilder typeBuilder, out MethodInfo saveMethod) + internal static AssemblyBuilder PopulateAssemblyBuilderAndTypeBuilder(out TypeBuilder typeBuilder) { - AssemblyBuilder ab = PopulateAssemblyBuilderAndSaveMethod(s_assemblyName, null, typeof(string), out saveMethod); + AssemblyBuilder ab = PopulateAssemblyBuilder(s_assemblyName, null); typeBuilder = ab.DefineDynamicModule("MyModule").DefineType("MyType", TypeAttributes.Public | TypeAttributes.Class); return ab; } - internal static AssemblyBuilder PopulateAssemblyBuilderAndSaveMethod(AssemblyName assemblyName, out MethodInfo saveMethod) => - PopulateAssemblyBuilderAndSaveMethod(assemblyName, null, typeof(string), out saveMethod); - - internal static AssemblyBuilder PopulateAssemblyBuilderAndSaveMethod(AssemblyName assemblyName, - List? assemblyAttributes, Type parameterType, out MethodInfo saveMethod) - { - Type assemblyType = Type.GetType("System.Reflection.Emit.AssemblyBuilderImpl, System.Reflection.Emit", throwOnError: true)!; - - saveMethod = assemblyType.GetMethod("Save", BindingFlags.NonPublic | BindingFlags.Instance, new Type[] { parameterType }); - - MethodInfo defineDynamicAssemblyMethod = assemblyType.GetMethod("DefinePersistedAssembly", BindingFlags.NonPublic | BindingFlags.Static, - new Type[] { typeof(AssemblyName), typeof(Assembly), typeof(List) }); - - return (AssemblyBuilder)defineDynamicAssemblyMethod.Invoke(null, - new object[] { assemblyName, CoreMetadataAssemblyResolver.s_coreAssembly, assemblyAttributes }); - } - - internal static Assembly LoadAssemblyFromPath(string filePath) => - new MetadataLoadContext(new CoreMetadataAssemblyResolver()).LoadFromAssemblyPath(filePath); + internal static AssemblyBuilder PopulateAssemblyBuilder(AssemblyName assemblyName, List? assemblyAttributes = null) => + AssemblyBuilder.DefinePersistedAssembly(assemblyName, CoreMetadataAssemblyResolver.s_coreAssembly, assemblyAttributes); internal static Assembly LoadAssemblyFromStream(Stream stream) => new MetadataLoadContext(new CoreMetadataAssemblyResolver()).LoadFromStream(stream); diff --git a/src/libraries/System.Reflection.Emit/tests/PersistableAssemblyBuilder/AssemblySaveTypeBuilderTests.cs b/src/libraries/System.Reflection.Emit/tests/PersistableAssemblyBuilder/AssemblySaveTypeBuilderTests.cs index 79b3f309d3d3ef..91d8ee4eb43397 100644 --- a/src/libraries/System.Reflection.Emit/tests/PersistableAssemblyBuilder/AssemblySaveTypeBuilderTests.cs +++ b/src/libraries/System.Reflection.Emit/tests/PersistableAssemblyBuilder/AssemblySaveTypeBuilderTests.cs @@ -25,20 +25,16 @@ public void EmptyAssemblyAndModuleTest() { using (TempFile file = TempFile.Create()) { - Assembly assemblyFromDisk = WriteAndLoadAssembly(Type.EmptyTypes, file.Path); - - Assert.Empty(assemblyFromDisk.GetTypes()); - AssemblySaveTools.AssertAssemblyNameAndModule(s_assemblyName, assemblyFromDisk.GetName(), assemblyFromDisk.Modules.FirstOrDefault()); + AssemblySaveTools.WriteAssemblyToDisk(s_assemblyName, Type.EmptyTypes, file.Path); + using (MetadataLoadContext mlc = new MetadataLoadContext(new CoreMetadataAssemblyResolver())) + { + Assembly assemblyFromDisk = mlc.LoadFromAssemblyPath(file.Path); + Assert.Empty(assemblyFromDisk.GetTypes()); + AssemblySaveTools.AssertAssemblyNameAndModule(s_assemblyName, assemblyFromDisk.GetName(), assemblyFromDisk.Modules.FirstOrDefault()); + } } } - private static Assembly WriteAndLoadAssembly(Type[] types, string filePath) - { - AssemblySaveTools.WriteAssemblyToDisk(s_assemblyName, types, filePath); - - return AssemblySaveTools.LoadAssemblyFromPath(filePath); - } - public static IEnumerable VariousInterfacesStructsTestData() { yield return new object[] { new Type[] { typeof(INoMethod) } }; @@ -58,9 +54,13 @@ public void WriteAssemblyWithVariousTypesToAFileAndReadBackTest(Type[] types) { using (TempFile file = TempFile.Create()) { - Assembly assemblyFromDisk = WriteAndLoadAssembly(types, file.Path); + AssemblySaveTools.WriteAssemblyToDisk(s_assemblyName, types, file.Path); - AssertTypesAndTypeMembers(types, assemblyFromDisk.Modules.First().GetTypes()); + using (MetadataLoadContext mlc = new MetadataLoadContext(new CoreMetadataAssemblyResolver())) + { + Assembly assemblyFromDisk = mlc.LoadFromAssemblyPath(file.Path); + AssertTypesAndTypeMembers(types, assemblyFromDisk.Modules.First().GetTypes()); + } } } @@ -97,30 +97,33 @@ public void CreateMembersThatUsesTypeLoadedFromCoreAssemblyTest() { using (TempFile file = TempFile.Create()) { - TypeBuilder tb = CreateAssemblyAndDefineType(out AssemblyBuilder assemblyBuilder, out MethodInfo saveMethod); + TypeBuilder tb = CreateAssemblyAndDefineType(out AssemblyBuilder assemblyBuilder); tb.DefineMethod("TestMethod", MethodAttributes.Public).GetILGenerator().Emit(OpCodes.Ret); tb.CreateType(); - saveMethod.Invoke(assemblyBuilder, new object[] { file.Path }); + assemblyBuilder.Save(file.Path); - Assembly assemblyFromDisk = AssemblySaveTools.LoadAssemblyFromPath(file.Path); - Module moduleFromDisk = assemblyFromDisk.Modules.First(); + using (MetadataLoadContext mlc = new MetadataLoadContext(new CoreMetadataAssemblyResolver())) + { + Assembly assemblyFromDisk = mlc.LoadFromAssemblyPath(file.Path); + Module moduleFromDisk = assemblyFromDisk.Modules.First(); - Assert.Equal("MyModule", moduleFromDisk.ScopeName); - Assert.Equal(1, moduleFromDisk.GetTypes().Length); + Assert.Equal("MyModule", moduleFromDisk.ScopeName); + Assert.Equal(1, moduleFromDisk.GetTypes().Length); - Type testType = moduleFromDisk.GetTypes()[0]; - Assert.Equal("TestInterface", testType.Name); + Type testType = moduleFromDisk.GetTypes()[0]; + Assert.Equal("TestInterface", testType.Name); - MethodInfo method = testType.GetMethods()[0]; - Assert.Equal("TestMethod", method.Name); - Assert.Empty(method.GetParameters()); - Assert.Equal("System.Void", method.ReturnType.FullName); + MethodInfo method = testType.GetMethods()[0]; + Assert.Equal("TestMethod", method.Name); + Assert.Empty(method.GetParameters()); + Assert.Equal("System.Void", method.ReturnType.FullName); + } } } - private static TypeBuilder CreateAssemblyAndDefineType(out AssemblyBuilder assemblyBuilder, out MethodInfo saveMethod) + private static TypeBuilder CreateAssemblyAndDefineType(out AssemblyBuilder assemblyBuilder) { - assemblyBuilder = AssemblySaveTools.PopulateAssemblyBuilderAndSaveMethod(s_assemblyName, null, typeof(string), out saveMethod); + assemblyBuilder = AssemblySaveTools.PopulateAssemblyBuilder(s_assemblyName); return assemblyBuilder.DefineDynamicModule("MyModule") .DefineType("TestInterface", TypeAttributes.Interface | TypeAttributes.Abstract); } @@ -130,29 +133,31 @@ public void AddInterfaceImplementationTest() { using (TempFile file = TempFile.Create()) { - AssemblyBuilder assemblyBuilder = AssemblySaveTools.PopulateAssemblyBuilderAndSaveMethod( - s_assemblyName, null, typeof(string), out MethodInfo saveMethod); + AssemblyBuilder assemblyBuilder = AssemblySaveTools.PopulateAssemblyBuilder(s_assemblyName); ModuleBuilder mb = assemblyBuilder.DefineDynamicModule("My Module"); - TypeBuilder tb = mb.DefineType("TestInterface", TypeAttributes.Interface | TypeAttributes.Abstract, null, new Type[] { typeof(IOneMethod)}); + TypeBuilder tb = mb.DefineType("TestInterface", TypeAttributes.Interface | TypeAttributes.Abstract, null, [typeof(IOneMethod)]); tb.AddInterfaceImplementation(typeof(INoMethod)); TypeBuilder nestedType = tb.DefineNestedType("NestedType", TypeAttributes.Interface | TypeAttributes.Abstract); tb.CreateType(); nestedType.CreateType(); - saveMethod.Invoke(assemblyBuilder, new object[] { file.Path }); - - Assembly assemblyFromDisk = AssemblySaveTools.LoadAssemblyFromPath(file.Path); - Type testType = assemblyFromDisk.Modules.First().GetTypes()[0]; - Type[] interfaces = testType.GetInterfaces(); + assemblyBuilder.Save(file.Path); - Assert.Equal("TestInterface", testType.Name); - Assert.Equal(2, interfaces.Length); - - Type iOneMethod = testType.GetInterface("IOneMethod"); - Type iNoMethod = testType.GetInterface("INoMethod"); - Type[] nt = testType.GetNestedTypes(); - Assert.Equal(1, iOneMethod.GetMethods().Length); - Assert.Empty(iNoMethod.GetMethods()); - Assert.NotNull(testType.GetNestedType("NestedType", BindingFlags.NonPublic)); + using (MetadataLoadContext mlc = new MetadataLoadContext(new CoreMetadataAssemblyResolver())) + { + Assembly assemblyFromDisk = mlc.LoadFromAssemblyPath(file.Path); + Type testType = assemblyFromDisk.Modules.First().GetTypes()[0]; + Type[] interfaces = testType.GetInterfaces(); + + Assert.Equal("TestInterface", testType.Name); + Assert.Equal(2, interfaces.Length); + + Type iOneMethod = testType.GetInterface("IOneMethod"); + Type iNoMethod = testType.GetInterface("INoMethod"); + Type[] nt = testType.GetNestedTypes(); + Assert.Equal(1, iOneMethod.GetMethods().Length); + Assert.Empty(iNoMethod.GetMethods()); + Assert.NotNull(testType.GetNestedType("NestedType", BindingFlags.NonPublic)); + } } } @@ -168,7 +173,7 @@ public void SaveGenericTypeParametersForAType(string[] typeParamNames) { using (TempFile file = TempFile.Create()) { - TypeBuilder tb = CreateAssemblyAndDefineType(out AssemblyBuilder assemblyBuilder, out MethodInfo saveMethod); + TypeBuilder tb = CreateAssemblyAndDefineType(out AssemblyBuilder assemblyBuilder); MethodBuilder method = tb.DefineMethod("TestMethod", MethodAttributes.Public); method.GetILGenerator().Emit(OpCodes.Ldarg_0); GenericTypeParameterBuilder[] typeParams = tb.DefineGenericParameters(typeParamNames); @@ -177,27 +182,31 @@ public void SaveGenericTypeParametersForAType(string[] typeParamNames) SetVariousGenericParameterValues(typeParams); } tb.CreateType(); - saveMethod.Invoke(assemblyBuilder, new object[] { file.Path }); - - Type testType = AssemblySaveTools.LoadAssemblyFromPath(file.Path).Modules.First().GetTypes()[0]; - MethodInfo testMethod = testType.GetMethod("TestMethod"); - Type[] genericTypeParams = testType.GetGenericArguments(); - - Assert.True(testType.IsGenericType); - Assert.True(testType.IsGenericTypeDefinition); - Assert.True(testType.ContainsGenericParameters); - Assert.False(testMethod.IsGenericMethod); - Assert.False(testMethod.IsGenericMethodDefinition); - Assert.True(testMethod.ContainsGenericParameters); - AssertGenericParameters(typeParams, genericTypeParams); + assemblyBuilder.Save(file.Path); + + using (MetadataLoadContext mlc = new MetadataLoadContext(new CoreMetadataAssemblyResolver())) + { + Assembly assemblyFromDisk = mlc.LoadFromAssemblyPath(file.Path); + Type testType = assemblyFromDisk.Modules.First().GetTypes()[0]; + MethodInfo testMethod = testType.GetMethod("TestMethod"); + Type[] genericTypeParams = testType.GetGenericArguments(); + + Assert.True(testType.IsGenericType); + Assert.True(testType.IsGenericTypeDefinition); + Assert.True(testType.ContainsGenericParameters); + Assert.False(testMethod.IsGenericMethod); + Assert.False(testMethod.IsGenericMethodDefinition); + Assert.True(testMethod.ContainsGenericParameters); + AssertGenericParameters(typeParams, genericTypeParams); + } } } private static void SetVariousGenericParameterValues(GenericTypeParameterBuilder[] typeParams) { - typeParams[0].SetInterfaceConstraints(new Type[] { typeof(IAccess), typeof(INoMethod) }); + typeParams[0].SetInterfaceConstraints([typeof(IAccess), typeof(INoMethod)]); typeParams[1].SetCustomAttribute(new CustomAttributeBuilder(typeof(DynamicallyAccessedMembersAttribute).GetConstructor( - new Type[] { typeof(DynamicallyAccessedMemberTypes) }), new object[] { DynamicallyAccessedMemberTypes.PublicProperties })); + [typeof(DynamicallyAccessedMemberTypes)]), [DynamicallyAccessedMemberTypes.PublicProperties])); typeParams[2].SetBaseTypeConstraint(typeof(EmptyTestClass)); typeParams[2].SetGenericParameterAttributes(GenericParameterAttributes.VarianceMask); } @@ -233,7 +242,7 @@ public void SaveGenericTypeParametersForAMethod(string[] typeParamNames) { using (TempFile file = TempFile.Create()) { - TypeBuilder tb = CreateAssemblyAndDefineType(out AssemblyBuilder assemblyBuilder, out MethodInfo saveMethod); + TypeBuilder tb = CreateAssemblyAndDefineType(out AssemblyBuilder assemblyBuilder); MethodBuilder method = tb.DefineMethod("TestMethod", MethodAttributes.Public); GenericTypeParameterBuilder[] typeParams = method.DefineGenericParameters(typeParamNames); method.GetILGenerator().Emit(OpCodes.Ldarg_0); @@ -242,19 +251,22 @@ public void SaveGenericTypeParametersForAMethod(string[] typeParamNames) SetVariousGenericParameterValues(typeParams); } tb.CreateType(); - saveMethod.Invoke(assemblyBuilder, new object[] { file.Path }); - - Type testType = AssemblySaveTools.LoadAssemblyFromPath(file.Path).Modules.First().GetTypes()[0]; - MethodInfo testMethod = testType.GetMethod("TestMethod"); - Type[] genericTypeParams = testMethod.GetGenericArguments(); - - Assert.False(testType.IsGenericType); - Assert.False(testType.IsGenericTypeDefinition); - Assert.False(testType.ContainsGenericParameters); - Assert.True(testMethod.IsGenericMethod); - Assert.True(testMethod.IsGenericMethodDefinition); - Assert.True(testMethod.ContainsGenericParameters); - AssertGenericParameters(typeParams, genericTypeParams); + assemblyBuilder.Save(file.Path); + + using (MetadataLoadContext mlc = new MetadataLoadContext(new CoreMetadataAssemblyResolver())) + { + Type testType = mlc.LoadFromAssemblyPath(file.Path).Modules.First().GetTypes()[0]; + MethodInfo testMethod = testType.GetMethod("TestMethod"); + Type[] genericTypeParams = testMethod.GetGenericArguments(); + + Assert.False(testType.IsGenericType); + Assert.False(testType.IsGenericTypeDefinition); + Assert.False(testType.ContainsGenericParameters); + Assert.True(testMethod.IsGenericMethod); + Assert.True(testMethod.IsGenericMethodDefinition); + Assert.True(testMethod.ContainsGenericParameters); + AssertGenericParameters(typeParams, genericTypeParams); + } } } @@ -267,25 +279,28 @@ public void SaveArrayTypeSignature(int rank, string name) { using (TempFile file = TempFile.Create()) { - TypeBuilder tb = CreateAssemblyAndDefineType(out AssemblyBuilder assemblyBuilder, out MethodInfo saveMethod); + TypeBuilder tb = CreateAssemblyAndDefineType(out AssemblyBuilder assemblyBuilder); Type arrayType = rank == 0 ? tb.MakeArrayType() : tb.MakeArrayType(rank); MethodBuilder mb = tb.DefineMethod("TestMethod", MethodAttributes.Public); mb.SetReturnType(arrayType); - mb.SetParameters(new Type[] { typeof(INoMethod), arrayType, typeof(int[,,,]) }); + mb.SetParameters([typeof(INoMethod), arrayType, typeof(int[,,,])]); mb.GetILGenerator().Emit(OpCodes.Ret); tb.CreateType(); - saveMethod.Invoke(assemblyBuilder, new object[] { file.Path }); - - Type testType = AssemblySaveTools.LoadAssemblyFromPath(file.Path).Modules.First().GetTypes()[0]; - MethodInfo testMethod = testType.GetMethod("TestMethod"); - Type intArray = testMethod.GetParameters()[2].ParameterType; - - Assert.False(testMethod.GetParameters()[0].ParameterType.IsSZArray); - Assert.True(intArray.IsArray); - Assert.Equal(4, intArray.GetArrayRank()); - Assert.Equal("Int32[,,,]", intArray.Name); - AssertArrayTypeSignature(rank, name, testMethod.ReturnType); - AssertArrayTypeSignature(rank, name, testMethod.GetParameters()[1].ParameterType); + assemblyBuilder.Save(file.Path); + + using (MetadataLoadContext mlc = new MetadataLoadContext(new CoreMetadataAssemblyResolver())) + { + Type testType = mlc.LoadFromAssemblyPath(file.Path).Modules.First().GetTypes()[0]; + MethodInfo testMethod = testType.GetMethod("TestMethod"); + Type intArray = testMethod.GetParameters()[2].ParameterType; + + Assert.False(testMethod.GetParameters()[0].ParameterType.IsSZArray); + Assert.True(intArray.IsArray); + Assert.Equal(4, intArray.GetArrayRank()); + Assert.Equal("Int32[,,,]", intArray.Name); + AssertArrayTypeSignature(rank, name, testMethod.ReturnType); + AssertArrayTypeSignature(rank, name, testMethod.GetParameters()[1].ParameterType); + } } } @@ -302,21 +317,24 @@ public void SaveByRefTypeSignature() { using (TempFile file = TempFile.Create()) { - TypeBuilder tb = CreateAssemblyAndDefineType(out AssemblyBuilder assemblyBuilder, out MethodInfo saveMethod); + TypeBuilder tb = CreateAssemblyAndDefineType(out AssemblyBuilder assemblyBuilder); Type byrefType = tb.MakeByRefType(); MethodBuilder mb = tb.DefineMethod("TestMethod", MethodAttributes.Public); mb.SetReturnType(byrefType); - mb.SetParameters(new Type[] { typeof(INoMethod), byrefType }); + mb.SetParameters([typeof(INoMethod), byrefType]); mb.GetILGenerator().Emit(OpCodes.Ret); tb.CreateType(); - saveMethod.Invoke(assemblyBuilder, new object[] { file.Path }); + assemblyBuilder.Save(file.Path); - Type testType = AssemblySaveTools.LoadAssemblyFromPath(file.Path).Modules.First().GetTypes()[0]; - MethodInfo testMethod = testType.GetMethod("TestMethod"); + using (MetadataLoadContext mlc = new MetadataLoadContext(new CoreMetadataAssemblyResolver())) + { + Type testType = mlc.LoadFromAssemblyPath(file.Path).Modules.First().GetTypes()[0]; + MethodInfo testMethod = testType.GetMethod("TestMethod"); - Assert.False(testMethod.GetParameters()[0].ParameterType.IsByRef); - AssertByRefType(testMethod.GetParameters()[1].ParameterType); - AssertByRefType(testMethod.ReturnType); + Assert.False(testMethod.GetParameters()[0].ParameterType.IsByRef); + AssertByRefType(testMethod.GetParameters()[1].ParameterType); + AssertByRefType(testMethod.ReturnType); + } } } @@ -331,21 +349,24 @@ public void SavePointerTypeSignature() { using (TempFile file = TempFile.Create()) { - TypeBuilder tb = CreateAssemblyAndDefineType(out AssemblyBuilder assemblyBuilder, out MethodInfo saveMethod); + TypeBuilder tb = CreateAssemblyAndDefineType(out AssemblyBuilder assemblyBuilder); Type pointerType = tb.MakePointerType(); MethodBuilder mb = tb.DefineMethod("TestMethod", MethodAttributes.Public); mb.SetReturnType(pointerType); - mb.SetParameters(new Type[] { typeof(INoMethod), pointerType }); + mb.SetParameters([typeof(INoMethod), pointerType]); mb.GetILGenerator().Emit(OpCodes.Ret); tb.CreateType(); - saveMethod.Invoke(assemblyBuilder, new object[] { file.Path }); + assemblyBuilder.Save(file.Path); - Type testType = AssemblySaveTools.LoadAssemblyFromPath(file.Path).Modules.First().GetTypes()[0]; - MethodInfo testMethod = testType.GetMethod("TestMethod"); + using (MetadataLoadContext mlc = new MetadataLoadContext(new CoreMetadataAssemblyResolver())) + { + Type testType = mlc.LoadFromAssemblyPath(file.Path).Modules.First().GetTypes()[0]; + MethodInfo testMethod = testType.GetMethod("TestMethod"); - Assert.False(testMethod.GetParameters()[0].ParameterType.IsPointer); - AssertPointerType(testMethod.GetParameters()[1].ParameterType); - AssertPointerType(testMethod.ReturnType); + Assert.False(testMethod.GetParameters()[0].ParameterType.IsPointer); + AssertPointerType(testMethod.GetParameters()[1].ParameterType); + AssertPointerType(testMethod.ReturnType); + } } } @@ -369,30 +390,33 @@ public void SaveGenericTypeSignature(string[] genericParams, Type[] typeArgument { using (TempFile file = TempFile.Create()) { - TypeBuilder tb = CreateAssemblyAndDefineType(out AssemblyBuilder assemblyBuilder, out MethodInfo saveMethod); + TypeBuilder tb = CreateAssemblyAndDefineType(out AssemblyBuilder assemblyBuilder); GenericTypeParameterBuilder[] typeGenParam = tb.DefineGenericParameters(genericParams); Type genericType = tb.MakeGenericType(typeArguments); MethodBuilder mb = tb.DefineMethod("TestMethod", MethodAttributes.Public); mb.SetReturnType(genericType); - mb.SetParameters(new Type[] { typeof(INoMethod), genericType }); + mb.SetParameters([typeof(INoMethod), genericType]); mb.GetILGenerator().Emit(OpCodes.Ret); tb.CreateType(); - saveMethod.Invoke(assemblyBuilder, new object[] { file.Path }); + assemblyBuilder.Save(file.Path); - Type testType = AssemblySaveTools.LoadAssemblyFromPath(file.Path).Modules.First().GetTypes()[0]; - MethodInfo testMethod = testType.GetMethod("TestMethod"); - Type paramType = testMethod.GetParameters()[1].ParameterType; + using (MetadataLoadContext mlc = new MetadataLoadContext(new CoreMetadataAssemblyResolver())) + { + Type testType = mlc.LoadFromAssemblyPath(file.Path).Modules.First().GetTypes()[0]; + MethodInfo testMethod = testType.GetMethod("TestMethod"); + Type paramType = testMethod.GetParameters()[1].ParameterType; - Assert.False(testMethod.GetParameters()[0].ParameterType.IsGenericType); - AssertGenericType(stringRepresentation, paramType); - AssertGenericType(stringRepresentation, testMethod.ReturnType); + Assert.False(testMethod.GetParameters()[0].ParameterType.IsGenericType); + AssertGenericType(stringRepresentation, paramType); + AssertGenericType(stringRepresentation, testMethod.ReturnType); + } } } [Fact] public void TypeBuilder_GetMethod_ReturnsMethod() { - AssemblySaveTools.PopulateAssemblyBuilderTypeBuilderAndSaveMethod(out TypeBuilder type, out MethodInfo _); + AssemblySaveTools.PopulateAssemblyBuilderAndTypeBuilder(out TypeBuilder type); type.DefineGenericParameters("T"); MethodBuilder genericMethod = type.DefineMethod("GM", MethodAttributes.Public | MethodAttributes.Static); @@ -412,7 +436,7 @@ public void TypeBuilder_GetMethod_ReturnsMethod() [Fact] public void TypeBuilder_GetField_DeclaringTypeOfFieldGeneric() { - AssemblySaveTools.PopulateAssemblyBuilderTypeBuilderAndSaveMethod(out TypeBuilder type, out MethodInfo _); + AssemblySaveTools.PopulateAssemblyBuilderAndTypeBuilder(out TypeBuilder type); GenericTypeParameterBuilder[] typeParams = type.DefineGenericParameters("T"); FieldBuilder field = type.DefineField("Field", typeParams[0].AsType(), FieldAttributes.Public); @@ -426,7 +450,7 @@ public void TypeBuilder_GetField_DeclaringTypeOfFieldGeneric() [Fact] public void GetField_TypeNotGeneric_ThrowsArgumentException() { - AssemblySaveTools.PopulateAssemblyBuilderTypeBuilderAndSaveMethod(out TypeBuilder type, out MethodInfo _); + AssemblySaveTools.PopulateAssemblyBuilderAndTypeBuilder(out TypeBuilder type); FieldBuilder field = type.DefineField("Field", typeof(int), FieldAttributes.Public); AssertExtensions.Throws("field", () => TypeBuilder.GetField(type, field)); @@ -447,36 +471,39 @@ public void SaveGenericTypeSignatureWithGenericParameter() { using (TempFile file = TempFile.Create()) { - TypeBuilder tb = CreateAssemblyAndDefineType(out AssemblyBuilder assemblyBuilder, out MethodInfo saveMethod); - GenericTypeParameterBuilder[] typeParams = tb.DefineGenericParameters(new string[] { "U", "T", "P" }); + TypeBuilder tb = CreateAssemblyAndDefineType(out AssemblyBuilder assemblyBuilder); + GenericTypeParameterBuilder[] typeParams = tb.DefineGenericParameters(["U", "T", "P"]); MethodBuilder mb = tb.DefineMethod("TestMethod", MethodAttributes.Public); - GenericTypeParameterBuilder[] methodParams = mb.DefineGenericParameters(new string[] { "M", "N" }); + GenericTypeParameterBuilder[] methodParams = mb.DefineGenericParameters(["M", "N"]); Type genericType = tb.MakeGenericType(typeParams); mb.SetReturnType(methodParams[0]); - mb.SetParameters(new Type[] { typeof(INoMethod), genericType, typeParams[1] }); + mb.SetParameters([typeof(INoMethod), genericType, typeParams[1]]); mb.GetILGenerator().Emit(OpCodes.Ret); tb.CreateType(); - saveMethod.Invoke(assemblyBuilder, new object[] { file.Path }); - - Type testType = AssemblySaveTools.LoadAssemblyFromPath(file.Path).Modules.First().GetTypes()[0]; - MethodInfo testMethod = testType.GetMethod("TestMethod"); - Type paramType = testMethod.GetParameters()[1].ParameterType; - Type genericParameter = testMethod.GetParameters()[2].ParameterType; - - Assert.False(testMethod.GetParameters()[0].ParameterType.IsGenericType); - AssertGenericType("TestInterface[U,T,P]", paramType); - Assert.False(genericParameter.IsGenericType); - Assert.True(genericParameter.IsGenericParameter); - Assert.False(genericParameter.IsGenericTypeDefinition); - Assert.True(genericParameter.IsGenericTypeParameter); - Assert.False(genericParameter.IsGenericMethodParameter); - Assert.Equal("T", genericParameter.Name); - Assert.False(testMethod.ReturnType.IsGenericType); - Assert.True(testMethod.ReturnType.IsGenericParameter); - Assert.False(testMethod.ReturnType.IsGenericTypeDefinition); - Assert.False(testMethod.ReturnType.IsGenericTypeParameter); - Assert.True(testMethod.ReturnType.IsGenericMethodParameter); - Assert.Equal("M", testMethod.ReturnType.Name); + assemblyBuilder.Save(file.Path); + + using (MetadataLoadContext mlc = new MetadataLoadContext(new CoreMetadataAssemblyResolver())) + { + Type testType = mlc.LoadFromAssemblyPath(file.Path).Modules.First().GetTypes()[0]; + MethodInfo testMethod = testType.GetMethod("TestMethod"); + Type paramType = testMethod.GetParameters()[1].ParameterType; + Type genericParameter = testMethod.GetParameters()[2].ParameterType; + + Assert.False(testMethod.GetParameters()[0].ParameterType.IsGenericType); + AssertGenericType("TestInterface[U,T,P]", paramType); + Assert.False(genericParameter.IsGenericType); + Assert.True(genericParameter.IsGenericParameter); + Assert.False(genericParameter.IsGenericTypeDefinition); + Assert.True(genericParameter.IsGenericTypeParameter); + Assert.False(genericParameter.IsGenericMethodParameter); + Assert.Equal("T", genericParameter.Name); + Assert.False(testMethod.ReturnType.IsGenericType); + Assert.True(testMethod.ReturnType.IsGenericParameter); + Assert.False(testMethod.ReturnType.IsGenericTypeDefinition); + Assert.False(testMethod.ReturnType.IsGenericTypeParameter); + Assert.True(testMethod.ReturnType.IsGenericMethodParameter); + Assert.Equal("M", testMethod.ReturnType.Name); + } } } @@ -485,63 +512,65 @@ public void SaveMultipleGenericTypeParametersToEnsureSortingWorks() { using (TempFile file = TempFile.Create()) { - AssemblyBuilder assemblyBuilder = AssemblySaveTools.PopulateAssemblyBuilderAndSaveMethod( - s_assemblyName, null, typeof(string), out MethodInfo saveMethod); + AssemblyBuilder assemblyBuilder = AssemblySaveTools.PopulateAssemblyBuilder(s_assemblyName); ModuleBuilder mb = assemblyBuilder.DefineDynamicModule("My Module"); TypeBuilder tb = mb.DefineType("TestInterface1", TypeAttributes.Interface | TypeAttributes.Abstract); - GenericTypeParameterBuilder[] typeParams = tb.DefineGenericParameters(new string[] { "U", "T" }); - typeParams[1].SetInterfaceConstraints(new [] { typeof(INoMethod), typeof(IOneMethod) }); + GenericTypeParameterBuilder[] typeParams = tb.DefineGenericParameters(["U", "T"]); + typeParams[1].SetInterfaceConstraints([typeof(INoMethod), typeof(IOneMethod)]); MethodBuilder m11 = tb.DefineMethod("TwoParameters", MethodAttributes.Public); MethodBuilder m12 = tb.DefineMethod("FiveTypeParameters", MethodAttributes.Public); MethodBuilder m13 = tb.DefineMethod("OneParameter", MethodAttributes.Public); - m11.DefineGenericParameters(new string[] { "M", "N" }); + m11.DefineGenericParameters(["M", "N"]); m11.GetILGenerator().Emit(OpCodes.Ret); - GenericTypeParameterBuilder[] methodParams = m12.DefineGenericParameters(new string[] { "A", "B", "C", "D", "F" }); + GenericTypeParameterBuilder[] methodParams = m12.DefineGenericParameters(["A", "B", "C", "D", "F"]); m12.GetILGenerator().Emit(OpCodes.Ret); - methodParams[2].SetInterfaceConstraints(new [] { typeof(IMultipleMethod) }); - m13.DefineGenericParameters(new string[] { "T" }); + methodParams[2].SetInterfaceConstraints([typeof(IMultipleMethod)]); + m13.DefineGenericParameters(["T"]); m13.GetILGenerator().Emit(OpCodes.Ret); TypeBuilder tb2 = mb.DefineType("TestInterface2", TypeAttributes.Interface | TypeAttributes.Abstract); - tb2.DefineGenericParameters(new string[] { "TFirst", "TSecond", "TThird" }); + tb2.DefineGenericParameters(["TFirst", "TSecond", "TThird"]); MethodBuilder m21 = tb2.DefineMethod("TestMethod", MethodAttributes.Public); - m21.DefineGenericParameters(new string[] { "X", "Y", "Z" }); + m21.DefineGenericParameters(["X", "Y", "Z"]); m21.GetILGenerator().Emit(OpCodes.Ret); TypeBuilder tb3 = mb.DefineType("TestType"); - GenericTypeParameterBuilder[] typePar = tb3.DefineGenericParameters(new string[] { "TOne" }); + GenericTypeParameterBuilder[] typePar = tb3.DefineGenericParameters(["TOne"]); typePar[0].SetBaseTypeConstraint(typeof(EmptyTestClass)); tb3.CreateType(); tb2.CreateType(); tb.CreateType(); - saveMethod.Invoke(assemblyBuilder, new object[] { file.Path }); - - Module m = AssemblySaveTools.LoadAssemblyFromPath(file.Path).Modules.First(); - Type[] type1Params = m.GetTypes()[2].GetGenericArguments(); - Type[] type2Params = m.GetTypes()[1].GetGenericArguments(); - Type[] type3Params = m.GetTypes()[0].GetGenericArguments(); - - Assert.Equal("U", type1Params[0].Name); - Assert.Empty(type1Params[0].GetTypeInfo().GetGenericParameterConstraints()); - Assert.Equal("T", type1Params[1].Name); - Assert.Equal(nameof(IOneMethod), type1Params[1].GetTypeInfo().GetGenericParameterConstraints()[1].Name); - Assert.Equal("TFirst", type2Params[0].Name); - Assert.Equal("TSecond", type2Params[1].Name); - Assert.Equal("TThird", type2Params[2].Name); - Assert.Equal("TOne", type3Params[0].Name); - Assert.Equal(nameof(EmptyTestClass), type3Params[0].GetTypeInfo().GetGenericParameterConstraints()[0].Name); - - Type[] method11Params = m.GetTypes()[2].GetMethod("TwoParameters").GetGenericArguments(); - Type[] method12Params = m.GetTypes()[2].GetMethod("FiveTypeParameters").GetGenericArguments(); - Assert.Equal(nameof(IMultipleMethod), method12Params[2].GetTypeInfo().GetGenericParameterConstraints()[0].Name); - Type[] method13Params = m.GetTypes()[2].GetMethod("OneParameter").GetGenericArguments(); - Type[] method21Params = m.GetTypes()[1].GetMethod("TestMethod").GetGenericArguments(); - - Assert.Equal("M", method11Params[0].Name); - Assert.Equal("N", method11Params[1].Name); - Assert.Equal("A", method12Params[0].Name); - Assert.Equal("F", method12Params[4].Name); - Assert.Equal("T", method13Params[0].Name); - Assert.Equal("X", method21Params[0].Name); - Assert.Equal("Z", method21Params[2].Name); + assemblyBuilder.Save(file.Path); + + using (MetadataLoadContext mlc = new MetadataLoadContext(new CoreMetadataAssemblyResolver())) + { + Module m = mlc.LoadFromAssemblyPath(file.Path).Modules.First(); + Type[] type1Params = m.GetTypes()[2].GetGenericArguments(); + Type[] type2Params = m.GetTypes()[1].GetGenericArguments(); + Type[] type3Params = m.GetTypes()[0].GetGenericArguments(); + + Assert.Equal("U", type1Params[0].Name); + Assert.Empty(type1Params[0].GetTypeInfo().GetGenericParameterConstraints()); + Assert.Equal("T", type1Params[1].Name); + Assert.Equal(nameof(IOneMethod), type1Params[1].GetTypeInfo().GetGenericParameterConstraints()[1].Name); + Assert.Equal("TFirst", type2Params[0].Name); + Assert.Equal("TSecond", type2Params[1].Name); + Assert.Equal("TThird", type2Params[2].Name); + Assert.Equal("TOne", type3Params[0].Name); + Assert.Equal(nameof(EmptyTestClass), type3Params[0].GetTypeInfo().GetGenericParameterConstraints()[0].Name); + + Type[] method11Params = m.GetTypes()[2].GetMethod("TwoParameters").GetGenericArguments(); + Type[] method12Params = m.GetTypes()[2].GetMethod("FiveTypeParameters").GetGenericArguments(); + Assert.Equal(nameof(IMultipleMethod), method12Params[2].GetTypeInfo().GetGenericParameterConstraints()[0].Name); + Type[] method13Params = m.GetTypes()[2].GetMethod("OneParameter").GetGenericArguments(); + Type[] method21Params = m.GetTypes()[1].GetMethod("TestMethod").GetGenericArguments(); + + Assert.Equal("M", method11Params[0].Name); + Assert.Equal("N", method11Params[1].Name); + Assert.Equal("A", method12Params[0].Name); + Assert.Equal("F", method12Params[4].Name); + Assert.Equal("T", method13Params[0].Name); + Assert.Equal("X", method21Params[0].Name); + Assert.Equal("Z", method21Params[2].Name); + } } } } diff --git a/src/libraries/System.Text.RegularExpressions/src/System/Text/RegularExpressions/RegexAssemblyCompiler.cs b/src/libraries/System.Text.RegularExpressions/src/System/Text/RegularExpressions/RegexAssemblyCompiler.cs index ff75e5d6534182..2e5dc74f733dce 100644 --- a/src/libraries/System.Text.RegularExpressions/src/System/Text/RegularExpressions/RegexAssemblyCompiler.cs +++ b/src/libraries/System.Text.RegularExpressions/src/System/Text/RegularExpressions/RegexAssemblyCompiler.cs @@ -27,7 +27,6 @@ internal sealed class RegexAssemblyCompiler : RegexCompiler private readonly AssemblyBuilder _assembly; private readonly ModuleBuilder _module; - private readonly MethodInfo _save; internal RegexAssemblyCompiler(AssemblyName an, CustomAttributeBuilder[]? attribs, string? resourceFile) { @@ -37,16 +36,8 @@ internal RegexAssemblyCompiler(AssemblyName an, CustomAttributeBuilder[]? attrib throw new PlatformNotSupportedException(); } - // TODO: Use public API when it's available: https://github.com/dotnet/runtime/issues/15704 - Type abType = Type.GetType("System.Reflection.Emit.AssemblyBuilderImpl, System.Reflection.Emit", throwOnError: true)!; - MethodInfo defineDynamicAssembly = abType.GetMethod("DefinePersistedAssembly", - BindingFlags.NonPublic | BindingFlags.Static, - [typeof(AssemblyName), typeof(Assembly), typeof(List)]) ?? - throw new InvalidOperationException("Could not find method AssemblyBuilderImpl.DefinePersistedAssembly"); - _assembly = (AssemblyBuilder?)defineDynamicAssembly.Invoke(null, [an, typeof(object).Assembly, attribs is not null ? new List(attribs) : null]) ?? + _assembly = AssemblyBuilder.DefinePersistedAssembly(an, typeof(object).Assembly, attribs is not null ? new List(attribs) : null) ?? throw new InvalidOperationException("DefinePersistedAssembly returned null"); - _save = abType.GetMethod("Save", BindingFlags.NonPublic | BindingFlags.Instance, [typeof(string)]) ?? - throw new InvalidOperationException("Could not find method AssemblyBuilderImpl.Save"); _module = _assembly.DefineDynamicModule(an.Name + ".dll"); } @@ -242,7 +233,7 @@ internal void Save(string fileName) fileName += ".dll"; } - _save.Invoke(_assembly, [fileName]); // TODO: Use public API when it's available: https://github.com/dotnet/runtime/issues/15704 + _assembly.Save(fileName); } /// Begins the definition of a new type with a specified base class From 7b79beae869dcf835e6e92ad80fc6522a5d767d8 Mon Sep 17 00:00:00 2001 From: Buyaa Namnan Date: Thu, 18 Jan 2024 16:57:24 -0800 Subject: [PATCH 3/8] Make AB.SaveCore(Stream) virtual and add meaningful message for excepiton thrown --- .../Reflection/Emit/RuntimeAssemblyBuilder.cs | 2 -- .../src/Resources/Strings.resx | 6 ++++++ .../System/Reflection/Emit/AssemblyBuilder.cs | 10 +++++----- .../ref/System.Reflection.Emit.cs | 2 +- ...piCompatBaseline.NetCoreAppLatestStable.xml | 18 ------------------ 5 files changed, 12 insertions(+), 26 deletions(-) diff --git a/src/coreclr/System.Private.CoreLib/src/System/Reflection/Emit/RuntimeAssemblyBuilder.cs b/src/coreclr/System.Private.CoreLib/src/System/Reflection/Emit/RuntimeAssemblyBuilder.cs index c07fc514b9caaf..fa3bfd25dac2f8 100644 --- a/src/coreclr/System.Private.CoreLib/src/System/Reflection/Emit/RuntimeAssemblyBuilder.cs +++ b/src/coreclr/System.Private.CoreLib/src/System/Reflection/Emit/RuntimeAssemblyBuilder.cs @@ -299,7 +299,5 @@ protected override void SetCustomAttributeCore(ConstructorInfo con, ReadOnlySpan binaryAttribute); } } - - protected override void SaveCore(Stream stream) => throw new NotSupportedException(); } } diff --git a/src/libraries/System.Private.CoreLib/src/Resources/Strings.resx b/src/libraries/System.Private.CoreLib/src/Resources/Strings.resx index 53cc0c13d1abb6..023650378b4d8b 100644 --- a/src/libraries/System.Private.CoreLib/src/Resources/Strings.resx +++ b/src/libraries/System.Private.CoreLib/src/Resources/Strings.resx @@ -4283,4 +4283,10 @@ This operation is not available because the reflection support was disabled at compile time. + + This AssemblyBuilder version doesn't support saving, use AssemblyBuilder.DefinePersistedAssembly(...) to get the AssemblyBuilder version that supports saving. + + + The constructor of the persisted 'AssemblyBuilder' type was null. + \ No newline at end of file diff --git a/src/libraries/System.Private.CoreLib/src/System/Reflection/Emit/AssemblyBuilder.cs b/src/libraries/System.Private.CoreLib/src/System/Reflection/Emit/AssemblyBuilder.cs index 812609599f273a..850518158bf212 100644 --- a/src/libraries/System.Private.CoreLib/src/System/Reflection/Emit/AssemblyBuilder.cs +++ b/src/libraries/System.Private.CoreLib/src/System/Reflection/Emit/AssemblyBuilder.cs @@ -47,14 +47,14 @@ public static AssemblyBuilder DefinePersistedAssembly(AssemblyName name, Assembl ArgumentNullException.ThrowIfNull(name); ArgumentNullException.ThrowIfNull(coreAssembly); - Type? assemblyType = Type.GetType("System.Reflection.Emit.AssemblyBuilderImpl, System.Reflection.Emit", throwOnError: true); + Type assemblyType = Type.GetType("System.Reflection.Emit.AssemblyBuilderImpl, System.Reflection.Emit", throwOnError: true)!; + ConstructorInfo? con = assemblyType.GetConstructor(BindingFlags.NonPublic | BindingFlags.Instance, [typeof(AssemblyName), typeof(Assembly), typeof(IEnumerable)]); - if (assemblyType == null) + if (con == null) { - throw new TypeLoadException(SR.Format(SR.TypeLoad_TypeNotFound, "System.Reflection.Emit.AssemblyBuilderImpl")); + throw new NullReferenceException(SR.NullReference_AssemblyBuilderConstructor); } - ConstructorInfo con = assemblyType.GetConstructor(BindingFlags.NonPublic | BindingFlags.Instance, [typeof(AssemblyName), typeof(Assembly), typeof(IEnumerable)])!; return (AssemblyBuilder)con.Invoke([name, coreAssembly, assemblyAttributes]); } @@ -84,7 +84,7 @@ public void Save(string assemblyFileName) /// When implemented in derived type serializer the assembly to stream. /// /// The stream to which the assembly serialized. - protected abstract void SaveCore(Stream stream); + protected virtual void SaveCore(Stream stream) => throw new NotSupportedException(""); public void SetCustomAttribute(ConstructorInfo con, byte[] binaryAttribute) { diff --git a/src/libraries/System.Reflection.Emit/ref/System.Reflection.Emit.cs b/src/libraries/System.Reflection.Emit/ref/System.Reflection.Emit.cs index 645265fedd2171..3863f7afa64d37 100644 --- a/src/libraries/System.Reflection.Emit/ref/System.Reflection.Emit.cs +++ b/src/libraries/System.Reflection.Emit/ref/System.Reflection.Emit.cs @@ -57,7 +57,7 @@ protected AssemblyBuilder() { } public override bool IsDefined(System.Type attributeType, bool inherit) { throw null; } public void Save(string assemblyFileName) { throw null; } public void Save(System.IO.Stream stream) { throw null; } - protected abstract void SaveCore(System.IO.Stream stream); + protected virtual void SaveCore(System.IO.Stream stream) { throw null; } public void SetCustomAttribute(System.Reflection.ConstructorInfo con, byte[] binaryAttribute) { } public void SetCustomAttribute(System.Reflection.Emit.CustomAttributeBuilder customBuilder) { } protected abstract void SetCustomAttributeCore(System.Reflection.ConstructorInfo con, System.ReadOnlySpan binaryAttribute); diff --git a/src/libraries/apicompat/ApiCompatBaseline.NetCoreAppLatestStable.xml b/src/libraries/apicompat/ApiCompatBaseline.NetCoreAppLatestStable.xml index 2e447a8ee7ad3c..2f7dfb841c805b 100644 --- a/src/libraries/apicompat/ApiCompatBaseline.NetCoreAppLatestStable.xml +++ b/src/libraries/apicompat/ApiCompatBaseline.NetCoreAppLatestStable.xml @@ -1,22 +1,4 @@  - - CP0005 - M:System.Reflection.Emit.AssemblyBuilder.SaveCore(System.IO.Stream) - net8.0/mscorlib.dll - net9.0/mscorlib.dll - - - CP0005 - M:System.Reflection.Emit.AssemblyBuilder.SaveCore(System.IO.Stream) - net8.0/netstandard.dll - net9.0/netstandard.dll - - - CP0005 - M:System.Reflection.Emit.AssemblyBuilder.SaveCore(System.IO.Stream) - net8.0/System.Reflection.Emit.dll - net9.0/System.Reflection.Emit.dll - \ No newline at end of file From 23304b667788b67b3ccc4bf1cac83a1a39d1a748 Mon Sep 17 00:00:00 2001 From: Buyaa Namnan Date: Thu, 18 Jan 2024 21:09:13 -0800 Subject: [PATCH 4/8] Apply suggestions from code review Co-authored-by: Stephen Toub Co-authored-by: Jan Kotas --- .../System.Private.CoreLib/src/Resources/Strings.resx | 2 +- .../src/System/Reflection/Emit/AssemblyBuilder.cs | 10 ++-------- .../ref/System.Reflection.Emit.cs | 2 +- 3 files changed, 4 insertions(+), 10 deletions(-) diff --git a/src/libraries/System.Private.CoreLib/src/Resources/Strings.resx b/src/libraries/System.Private.CoreLib/src/Resources/Strings.resx index 023650378b4d8b..76e72946cb2861 100644 --- a/src/libraries/System.Private.CoreLib/src/Resources/Strings.resx +++ b/src/libraries/System.Private.CoreLib/src/Resources/Strings.resx @@ -4284,7 +4284,7 @@ This operation is not available because the reflection support was disabled at compile time. - This AssemblyBuilder version doesn't support saving, use AssemblyBuilder.DefinePersistedAssembly(...) to get the AssemblyBuilder version that supports saving. + This AssemblyBuilder instance doesn't support saving. Use AssemblyBuilder.DefinePersistedAssembly to create an AssemblyBuilder instance that supports saving. The constructor of the persisted 'AssemblyBuilder' type was null. diff --git a/src/libraries/System.Private.CoreLib/src/System/Reflection/Emit/AssemblyBuilder.cs b/src/libraries/System.Private.CoreLib/src/System/Reflection/Emit/AssemblyBuilder.cs index 850518158bf212..9035f306385b28 100644 --- a/src/libraries/System.Private.CoreLib/src/System/Reflection/Emit/AssemblyBuilder.cs +++ b/src/libraries/System.Private.CoreLib/src/System/Reflection/Emit/AssemblyBuilder.cs @@ -48,13 +48,7 @@ public static AssemblyBuilder DefinePersistedAssembly(AssemblyName name, Assembl ArgumentNullException.ThrowIfNull(coreAssembly); Type assemblyType = Type.GetType("System.Reflection.Emit.AssemblyBuilderImpl, System.Reflection.Emit", throwOnError: true)!; - ConstructorInfo? con = assemblyType.GetConstructor(BindingFlags.NonPublic | BindingFlags.Instance, [typeof(AssemblyName), typeof(Assembly), typeof(IEnumerable)]); - - if (con == null) - { - throw new NullReferenceException(SR.NullReference_AssemblyBuilderConstructor); - } - + ConstructorInfo con = assemblyType.GetConstructor(BindingFlags.NonPublic | BindingFlags.Instance, [typeof(AssemblyName), typeof(Assembly), typeof(IEnumerable)])!; return (AssemblyBuilder)con.Invoke([name, coreAssembly, assemblyAttributes]); } @@ -84,7 +78,7 @@ public void Save(string assemblyFileName) /// When implemented in derived type serializer the assembly to stream. /// /// The stream to which the assembly serialized. - protected virtual void SaveCore(Stream stream) => throw new NotSupportedException(""); + protected virtual void SaveCore(Stream stream) => throw new NotSupportedException(SR.NotSupported_AssemblySave); public void SetCustomAttribute(ConstructorInfo con, byte[] binaryAttribute) { diff --git a/src/libraries/System.Reflection.Emit/ref/System.Reflection.Emit.cs b/src/libraries/System.Reflection.Emit/ref/System.Reflection.Emit.cs index 3863f7afa64d37..1cd9aa71da7432 100644 --- a/src/libraries/System.Reflection.Emit/ref/System.Reflection.Emit.cs +++ b/src/libraries/System.Reflection.Emit/ref/System.Reflection.Emit.cs @@ -57,7 +57,7 @@ protected AssemblyBuilder() { } public override bool IsDefined(System.Type attributeType, bool inherit) { throw null; } public void Save(string assemblyFileName) { throw null; } public void Save(System.IO.Stream stream) { throw null; } - protected virtual void SaveCore(System.IO.Stream stream) { throw null; } + protected virtual void SaveCore(System.IO.Stream stream) { } public void SetCustomAttribute(System.Reflection.ConstructorInfo con, byte[] binaryAttribute) { } public void SetCustomAttribute(System.Reflection.Emit.CustomAttributeBuilder customBuilder) { } protected abstract void SetCustomAttributeCore(System.Reflection.ConstructorInfo con, System.ReadOnlySpan binaryAttribute); From f854c54b946e39a3cc9e7479f274f69bb3077fd2 Mon Sep 17 00:00:00 2001 From: Buyaa Namnan Date: Thu, 18 Jan 2024 21:11:08 -0800 Subject: [PATCH 5/8] Remove unneeded message --- .../System.Private.CoreLib/src/Resources/Strings.resx | 3 --- 1 file changed, 3 deletions(-) diff --git a/src/libraries/System.Private.CoreLib/src/Resources/Strings.resx b/src/libraries/System.Private.CoreLib/src/Resources/Strings.resx index 76e72946cb2861..ac1309ebe08be5 100644 --- a/src/libraries/System.Private.CoreLib/src/Resources/Strings.resx +++ b/src/libraries/System.Private.CoreLib/src/Resources/Strings.resx @@ -4286,7 +4286,4 @@ This AssemblyBuilder instance doesn't support saving. Use AssemblyBuilder.DefinePersistedAssembly to create an AssemblyBuilder instance that supports saving. - - The constructor of the persisted 'AssemblyBuilder' type was null. - \ No newline at end of file From 444225b6d64fbd870f1d94911576beba6a2713f3 Mon Sep 17 00:00:00 2001 From: Buyaa Namnan Date: Thu, 18 Jan 2024 21:19:54 -0800 Subject: [PATCH 6/8] Apply suggestions from code review --- .../src/System/Reflection/Emit/AssemblyBuilder.cs | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/src/libraries/System.Private.CoreLib/src/System/Reflection/Emit/AssemblyBuilder.cs b/src/libraries/System.Private.CoreLib/src/System/Reflection/Emit/AssemblyBuilder.cs index 9035f306385b28..e48490e481ab18 100644 --- a/src/libraries/System.Private.CoreLib/src/System/Reflection/Emit/AssemblyBuilder.cs +++ b/src/libraries/System.Private.CoreLib/src/System/Reflection/Emit/AssemblyBuilder.cs @@ -58,14 +58,16 @@ public static AssemblyBuilder DefinePersistedAssembly(AssemblyName name, Assembl /// Serializes the assembly to stream. /// /// The stream to which the assembly serialized. - /// is null + /// is null. + /// The AssemblyBuilder instance doesn't support saving. public void Save(Stream stream) => SaveCore(stream); /// /// Saves the assembly to disk. /// /// The file name of the assembly. - /// is null + /// is null. + /// The AssemblyBuilder instance doesn't support saving. public void Save(string assemblyFileName) { ArgumentNullException.ThrowIfNull(assemblyFileName); From eaa743441cd83140dc03ebe6c36694a68386fe60 Mon Sep 17 00:00:00 2001 From: Buyaa Namnan Date: Fri, 19 Jan 2024 11:35:55 -0800 Subject: [PATCH 7/8] Apply feedbacks --- .../src/System/Reflection/Emit/AssemblyBuilder.cs | 7 ++++--- .../src/System/Reflection/Emit/AssemblyBuilderImpl.cs | 6 +----- .../tests/PersistableAssemblyBuilder/AssemblySaveTools.cs | 3 --- .../AssemblySaveTypeBuilderTests.cs | 7 +++++-- 4 files changed, 10 insertions(+), 13 deletions(-) diff --git a/src/libraries/System.Private.CoreLib/src/System/Reflection/Emit/AssemblyBuilder.cs b/src/libraries/System.Private.CoreLib/src/System/Reflection/Emit/AssemblyBuilder.cs index e48490e481ab18..8599d39aa4b166 100644 --- a/src/libraries/System.Private.CoreLib/src/System/Reflection/Emit/AssemblyBuilder.cs +++ b/src/libraries/System.Private.CoreLib/src/System/Reflection/Emit/AssemblyBuilder.cs @@ -45,6 +45,7 @@ public ModuleBuilder DefineDynamicModule(string name) public static AssemblyBuilder DefinePersistedAssembly(AssemblyName name, Assembly coreAssembly, IEnumerable? assemblyAttributes = null) { ArgumentNullException.ThrowIfNull(name); + ArgumentException.ThrowIfNullOrEmpty(name.Name, "AssemblyName.Name"); ArgumentNullException.ThrowIfNull(coreAssembly); Type assemblyType = Type.GetType("System.Reflection.Emit.AssemblyBuilderImpl, System.Reflection.Emit", throwOnError: true)!; @@ -55,9 +56,9 @@ public static AssemblyBuilder DefinePersistedAssembly(AssemblyName name, Assembl protected abstract ModuleBuilder? GetDynamicModuleCore(string name); /// - /// Serializes the assembly to stream. + /// Serializes the assembly to . /// - /// The stream to which the assembly serialized. + /// The to which the assembly serialized. /// is null. /// The AssemblyBuilder instance doesn't support saving. public void Save(Stream stream) => SaveCore(stream); @@ -77,7 +78,7 @@ public void Save(string assemblyFileName) } /// - /// When implemented in derived type serializer the assembly to stream. + /// When implemented in a derived type, serializes the assembly to a stream. /// /// The stream to which the assembly serialized. protected virtual void SaveCore(Stream stream) => throw new NotSupportedException(SR.NotSupported_AssemblySave); diff --git a/src/libraries/System.Reflection.Emit/src/System/Reflection/Emit/AssemblyBuilderImpl.cs b/src/libraries/System.Reflection.Emit/src/System/Reflection/Emit/AssemblyBuilderImpl.cs index 215745a5048284..87e12225fe310c 100644 --- a/src/libraries/System.Reflection.Emit/src/System/Reflection/Emit/AssemblyBuilderImpl.cs +++ b/src/libraries/System.Reflection.Emit/src/System/Reflection/Emit/AssemblyBuilderImpl.cs @@ -21,11 +21,7 @@ internal sealed class AssemblyBuilderImpl : AssemblyBuilder internal AssemblyBuilderImpl(AssemblyName name, Assembly coreAssembly, IEnumerable? assemblyAttributes = null) { - name = (AssemblyName)name.Clone(); - - ArgumentException.ThrowIfNullOrEmpty(name.Name, "AssemblyName.Name"); - - _assemblyName = name; + _assemblyName = (AssemblyName)name.Clone(); _coreAssembly = coreAssembly; _metadataBuilder = new MetadataBuilder(); diff --git a/src/libraries/System.Reflection.Emit/tests/PersistableAssemblyBuilder/AssemblySaveTools.cs b/src/libraries/System.Reflection.Emit/tests/PersistableAssemblyBuilder/AssemblySaveTools.cs index 46beedf8cbb93b..43a670286d6640 100644 --- a/src/libraries/System.Reflection.Emit/tests/PersistableAssemblyBuilder/AssemblySaveTools.cs +++ b/src/libraries/System.Reflection.Emit/tests/PersistableAssemblyBuilder/AssemblySaveTools.cs @@ -71,9 +71,6 @@ internal static AssemblyBuilder PopulateAssemblyBuilderAndTypeBuilder(out TypeBu internal static AssemblyBuilder PopulateAssemblyBuilder(AssemblyName assemblyName, List? assemblyAttributes = null) => AssemblyBuilder.DefinePersistedAssembly(assemblyName, CoreMetadataAssemblyResolver.s_coreAssembly, assemblyAttributes); - internal static Assembly LoadAssemblyFromStream(Stream stream) => - new MetadataLoadContext(new CoreMetadataAssemblyResolver()).LoadFromStream(stream); - internal static void AssertAssemblyNameAndModule(AssemblyName sourceAName, AssemblyName aNameFromDisk, Module moduleFromDisk) { // Runtime assemblies adding AssemblyNameFlags.PublicKey in Assembly.GetName() overloads diff --git a/src/libraries/System.Reflection.Emit/tests/PersistableAssemblyBuilder/AssemblySaveTypeBuilderTests.cs b/src/libraries/System.Reflection.Emit/tests/PersistableAssemblyBuilder/AssemblySaveTypeBuilderTests.cs index 91d8ee4eb43397..75be4000a7dd0a 100644 --- a/src/libraries/System.Reflection.Emit/tests/PersistableAssemblyBuilder/AssemblySaveTypeBuilderTests.cs +++ b/src/libraries/System.Reflection.Emit/tests/PersistableAssemblyBuilder/AssemblySaveTypeBuilderTests.cs @@ -86,9 +86,12 @@ public void WriteAssemblyWithVariousTypesToStreamAndReadBackTest(Type[] types) using (var stream = new MemoryStream()) { AssemblySaveTools.WriteAssemblyToStream(s_assemblyName, types, stream); - Assembly assemblyFromStream = AssemblySaveTools.LoadAssemblyFromStream(stream); - AssertTypesAndTypeMembers(types, assemblyFromStream.Modules.First().GetTypes()); + using (MetadataLoadContext mlc = new MetadataLoadContext(new CoreMetadataAssemblyResolver())) + { + Assembly assemblyFromStream = mlc.LoadFromStream(stream); + AssertTypesAndTypeMembers(types, assemblyFromStream.Modules.First().GetTypes()); + } } } From d1e8d20c607d6d2cf099144251ea676d0237cfcc Mon Sep 17 00:00:00 2001 From: Buyaa Namnan Date: Fri, 19 Jan 2024 15:02:08 -0800 Subject: [PATCH 8/8] Update newer tests to use new public APIs --- .../AssemblySaveModuleBuilderTests.cs | 24 +++++++++---------- .../AssemblySaveTypeBuilderAPIsTests.cs | 20 ++++++++-------- .../AssemblySaveTypeBuilderTests.cs | 10 ++++---- 3 files changed, 27 insertions(+), 27 deletions(-) diff --git a/src/libraries/System.Reflection.Emit/tests/PersistableAssemblyBuilder/AssemblySaveModuleBuilderTests.cs b/src/libraries/System.Reflection.Emit/tests/PersistableAssemblyBuilder/AssemblySaveModuleBuilderTests.cs index 6a3bb1e4dcbcbc..e6b5405ed81cb0 100644 --- a/src/libraries/System.Reflection.Emit/tests/PersistableAssemblyBuilder/AssemblySaveModuleBuilderTests.cs +++ b/src/libraries/System.Reflection.Emit/tests/PersistableAssemblyBuilder/AssemblySaveModuleBuilderTests.cs @@ -15,7 +15,7 @@ public void DefineGlobalMethodAndCreateGlobalFunctionsTest() { using (TempFile file = TempFile.Create()) { - AssemblyBuilder ab = AssemblySaveTools.PopulateAssemblyBuilderAndSaveMethod(new AssemblyName("MyAssembly"), out MethodInfo saveMethod); + AssemblyBuilder ab = AssemblySaveTools.PopulateAssemblyBuilder(new AssemblyName("MyAssembly")); ModuleBuilder module = ab.DefineDynamicModule("MyModule"); MethodBuilder method = module.DefineGlobalMethod("TestMethod", MethodAttributes.Static | MethodAttributes.Public, null, null); ILGenerator ilGenerator = method.GetILGenerator(); @@ -36,7 +36,7 @@ public void DefineGlobalMethodAndCreateGlobalFunctionsTest() Assert.Equal(method2, module.GetMethod("MyMethod", [typeof(string), typeof(int)])); Assert.Equal(2, module.GetMethods().Length); - saveMethod.Invoke(ab, [file.Path]); + ab.Save(file.Path); using (MetadataLoadContext mlc = new MetadataLoadContext(new CoreMetadataAssemblyResolver())) { @@ -63,7 +63,7 @@ public void DefineGlobalMethodAndCreateGlobalFunctionsTest() [Fact] public void DefineGlobalMethodAndCreateGlobalFunctions_Validations() { - AssemblyBuilder ab = AssemblySaveTools.PopulateAssemblyBuilderAndSaveMethod(new AssemblyName("MyAssembly"), out MethodInfo _); + AssemblyBuilder ab = AssemblySaveTools.PopulateAssemblyBuilder(new AssemblyName("MyAssembly")); ModuleBuilder module = ab.DefineDynamicModule("MyModule"); Assert.Throws(() => module.DefineGlobalMethod("TestMethod", MethodAttributes.Public, null, null)); // must be static MethodBuilder method = module.DefineGlobalMethod("TestMethod", MethodAttributes.Static | MethodAttributes.Public, null, null); @@ -85,7 +85,7 @@ public static void DefinePInvokeMethodTest() { using (TempFile file = TempFile.Create()) { - AssemblyBuilder ab = AssemblySaveTools.PopulateAssemblyBuilderAndSaveMethod(new AssemblyName("MyAssembly"), out MethodInfo saveMethod); + AssemblyBuilder ab = AssemblySaveTools.PopulateAssemblyBuilder(new AssemblyName("MyAssembly")); DpmParams p = new DpmParams() { MethodName = "A2", LibName = "Foo2.dll", EntrypointName = "Wha2", ReturnType = typeof(int), ParameterTypes = [typeof(int)], NativeCallConv = CallingConvention.Cdecl }; @@ -95,7 +95,7 @@ public static void DefinePInvokeMethodTest() mb.SetImplementationFlags(mb.GetMethodImplementationFlags() | MethodImplAttributes.PreserveSig); modb.CreateGlobalFunctions(); - saveMethod.Invoke(ab, [file.Path]); + ab.Save(file.Path); MethodInfo m = modb.GetMethod(p.MethodName, BindingFlags.Public | BindingFlags.NonPublic | BindingFlags.Static, null, CallingConventions.Any, p.ParameterTypes, null); Assert.NotNull(m); @@ -117,7 +117,7 @@ public static void DefinePInvokeMethodTest() [InlineData(FieldAttributes.Assembly | FieldAttributes.SpecialName)] public void DefineUninitializedDataTest(FieldAttributes attributes) { - AssemblyBuilder ab = AssemblySaveTools.PopulateAssemblyBuilderAndSaveMethod(new AssemblyName("MyAssembly"), out MethodInfo _); + AssemblyBuilder ab = AssemblySaveTools.PopulateAssemblyBuilder(new AssemblyName("MyAssembly")); ModuleBuilder module = ab.DefineDynamicModule("MyModule"); foreach (int size in new int[] { 1, 2, 0x003f0000 - 1 }) { @@ -133,7 +133,7 @@ public void DefineUninitializedDataTest(FieldAttributes attributes) [Fact] public void DefineUninitializedData_Validations() { - AssemblyBuilder ab = AssemblySaveTools.PopulateAssemblyBuilderAndSaveMethod(new AssemblyName("MyAssembly"), out MethodInfo _); + AssemblyBuilder ab = AssemblySaveTools.PopulateAssemblyBuilder(new AssemblyName("MyAssembly")); ModuleBuilder module = ab.DefineDynamicModule("MyModule"); AssertExtensions.Throws("name", () => module.DefineUninitializedData(null, 1, FieldAttributes.Family)); @@ -154,7 +154,7 @@ public void DefineUninitializedData_Validations() [InlineData(FieldAttributes.Private)] public void DefineInitializedDataTest(FieldAttributes attributes) { - AssemblyBuilder ab = AssemblySaveTools.PopulateAssemblyBuilderAndSaveMethod(new AssemblyName("MyAssembly"), out MethodInfo _); + AssemblyBuilder ab = AssemblySaveTools.PopulateAssemblyBuilder(new AssemblyName("MyAssembly")); ModuleBuilder module = ab.DefineDynamicModule("MyModule"); FieldBuilder field = module.DefineInitializedData("MyField", [01, 00, 01], attributes); @@ -167,7 +167,7 @@ public void DefineInitializedDataTest(FieldAttributes attributes) [Fact] public void DefineInitializedData_Validations() { - AssemblyBuilder ab = AssemblySaveTools.PopulateAssemblyBuilderAndSaveMethod(new AssemblyName("MyAssembly"), out MethodInfo _); + AssemblyBuilder ab = AssemblySaveTools.PopulateAssemblyBuilder(new AssemblyName("MyAssembly")); ModuleBuilder module = ab.DefineDynamicModule("MyModule"); AssertExtensions.Throws("name", () => module.DefineInitializedData(null, [1, 0, 1], FieldAttributes.Public)); @@ -190,7 +190,7 @@ public void DefineInitializedData_EnsureAlignmentIsMinimumNeededForUseOfCreateSp { using (TempFile file = TempFile.Create()) { - AssemblyBuilder ab = AssemblySaveTools.PopulateAssemblyBuilderAndSaveMethod(new AssemblyName("MyAssembly"), out MethodInfo saveMethod); + AssemblyBuilder ab = AssemblySaveTools.PopulateAssemblyBuilder(new AssemblyName("MyAssembly")); ModuleBuilder module = ab.DefineDynamicModule("MyModule"); TypeBuilder tb = module.DefineType("MyType", TypeAttributes.Public); // Create static field data in a variety of orders that requires the runtime to actively apply alignment @@ -232,7 +232,7 @@ void CreateLoadAddressMethod(string name, FieldBuilder fieldBuilder) } checkTypeBuilder.CreateType(); - saveMethod.Invoke(ab, [file.Path]); + ab.Save(file.Path); TestAssemblyLoadContext tlc = new TestAssemblyLoadContext(); Assembly assemblyFromDisk = tlc.LoadFromAssemblyPath(file.Path); @@ -265,7 +265,7 @@ void CheckMethod(string name, int minAlignmentRequired, byte[] dataToVerify) [ActiveIssue("https://github.com/dotnet/runtime/issues/96389", TestRuntimes.Mono)] public void GetABCMetadataToken_Validations() { - AssemblyBuilder ab = AssemblySaveTools.PopulateAssemblyBuilderAndSaveMethod(new AssemblyName("MyAssembly"), out MethodInfo _); + AssemblyBuilder ab = AssemblySaveTools.PopulateAssemblyBuilder(new AssemblyName("MyAssembly")); ModuleBuilder module = ab.DefineDynamicModule("MyModule"); TypeBuilder type = module.DefineType("MyType", TypeAttributes.Public); MethodBuilder method = type.DefineMethod("TestMethod", MethodAttributes.Static | MethodAttributes.Public); diff --git a/src/libraries/System.Reflection.Emit/tests/PersistableAssemblyBuilder/AssemblySaveTypeBuilderAPIsTests.cs b/src/libraries/System.Reflection.Emit/tests/PersistableAssemblyBuilder/AssemblySaveTypeBuilderAPIsTests.cs index f6c8b09d37cd60..e38e3e1d6582cd 100644 --- a/src/libraries/System.Reflection.Emit/tests/PersistableAssemblyBuilder/AssemblySaveTypeBuilderAPIsTests.cs +++ b/src/libraries/System.Reflection.Emit/tests/PersistableAssemblyBuilder/AssemblySaveTypeBuilderAPIsTests.cs @@ -434,14 +434,14 @@ public void ReturnTypeAndParameterRequiredOptionalCustomModifiers() Type[] cmodsReq2 = [typeof(uint)]; Type[] cmodsOpt1 = [typeof(int)]; Type[] cmodsOpt2 = [typeof(long), typeof(byte), typeof(bool)]; - AssemblyBuilder ab = AssemblySaveTools.PopulateAssemblyBuilderTypeBuilderAndSaveMethod(out TypeBuilder type, out MethodInfo saveMethod); + AssemblyBuilder ab = AssemblySaveTools.PopulateAssemblyBuilderAndTypeBuilder(out TypeBuilder type); MethodBuilder methodAll = type.DefineMethod("AllModifiers", MethodAttributes.Public | MethodAttributes.Static, CallingConventions.Standard, typeof(string), [typeof(int), typeof(short)], [typeof(Version)], [typeof(int), typeof(long)], [cmodsReq1, cmodsReq2], [cmodsOpt1, cmodsOpt2]); ILGenerator ilGenerator = methodAll.GetILGenerator(); ilGenerator.Emit(OpCodes.Ldstr, "Hello World"); ilGenerator.Emit(OpCodes.Ret); Type createdType = type.CreateType(); - saveMethod.Invoke(ab, [file.Path]); + ab.Save(file.Path); using (MetadataLoadContext mlc = new MetadataLoadContext(new CoreMetadataAssemblyResolver())) { @@ -475,7 +475,7 @@ public static void DefinePInvokeMethodExecution_Windows() using (TempFile file = TempFile.Create()) { - AssemblyBuilder ab = AssemblySaveTools.PopulateAssemblyBuilderAndSaveMethod(new AssemblyName("DefinePInvokeMethodExecution_Windows"), out MethodInfo saveMethod); + AssemblyBuilder ab = AssemblySaveTools.PopulateAssemblyBuilder(new AssemblyName("DefinePInvokeMethodExecution_Windows")); TypeBuilder tb = ab.DefineDynamicModule("MyModule").DefineType("MyType", TypeAttributes.Public | TypeAttributes.Class); MethodBuilder mb = tb.DefinePInvokeMethod( "GetEnvironmentVariableW", @@ -489,7 +489,7 @@ public static void DefinePInvokeMethodExecution_Windows() mb.SetImplementationFlags(mb.GetMethodImplementationFlags() | MethodImplAttributes.PreserveSig); Type t = tb.CreateType(); - saveMethod.Invoke(ab, [file.Path]); + ab.Save(file.Path); TestAssemblyLoadContext tlc = new TestAssemblyLoadContext(); Assembly assemblyFromDisk = tlc.LoadFromAssemblyPath(file.Path); @@ -544,12 +544,12 @@ public static void TestDefinePInvokeMethod(DpmParams p) { using (TempFile file = TempFile.Create()) { - AssemblyBuilder ab = AssemblySaveTools.PopulateAssemblyBuilderTypeBuilderAndSaveMethod(out TypeBuilder tb, out MethodInfo saveMethod); + AssemblyBuilder ab = AssemblySaveTools.PopulateAssemblyBuilderAndTypeBuilder(out TypeBuilder tb); MethodBuilder mb = tb.DefinePInvokeMethod(p.MethodName, p.LibName, p.EntrypointName, p.Attributes, p.ManagedCallConv, p.ReturnType, p.ReturnTypeReqMods, p.ReturnTypeOptMods, p.ParameterTypes, p.ParameterTypeReqMods, p.ParameterTypeOptMods, p.NativeCallConv, p.Charset); mb.SetImplementationFlags(mb.GetMethodImplementationFlags() | MethodImplAttributes.PreserveSig); Type t = tb.CreateType(); - saveMethod.Invoke(ab, [file.Path]); + ab.Save(file.Path); using (MetadataLoadContext mlc = new MetadataLoadContext(new CoreMetadataAssemblyResolver())) { @@ -676,7 +676,7 @@ public void DefineTypeInitializer() { using (TempFile file = TempFile.Create()) { - AssemblyBuilder ab = AssemblySaveTools.PopulateAssemblyBuilderTypeBuilderAndSaveMethod(out TypeBuilder tb, out MethodInfo saveMethod); + AssemblyBuilder ab = AssemblySaveTools.PopulateAssemblyBuilderAndTypeBuilder(out TypeBuilder tb); FieldBuilder greetingField = tb.DefineField("Greeting", typeof(string), FieldAttributes.Private | FieldAttributes.Static); ConstructorBuilder constructor = tb.DefineTypeInitializer(); ILGenerator constructorIlGenerator = constructor.GetILGenerator(); @@ -685,7 +685,7 @@ public void DefineTypeInitializer() constructorIlGenerator.Emit(OpCodes.Ret); tb.CreateType(); - saveMethod.Invoke(ab, [file.Path]); + ab.Save(file.Path); TestAssemblyLoadContext tlc = new TestAssemblyLoadContext(); Type typeFromDisk = tlc.LoadFromAssemblyPath(file.Path).GetType("MyType"); @@ -700,7 +700,7 @@ public static void DefineUninitializedDataTest() { using (TempFile file = TempFile.Create()) { - AssemblyBuilder ab = AssemblySaveTools.PopulateAssemblyBuilderTypeBuilderAndSaveMethod(out TypeBuilder tb, out MethodInfo saveMethod); + AssemblyBuilder ab = AssemblySaveTools.PopulateAssemblyBuilderAndTypeBuilder(out TypeBuilder tb); FieldBuilder myFieldBuilder = tb.DefineUninitializedData("MyGreeting", 4, FieldAttributes.Public); var loadAddressMethod = tb.DefineMethod("LoadAddress", MethodAttributes.Public | MethodAttributes.Static, typeof(IntPtr), null); var methodIL = loadAddressMethod.GetILGenerator(); @@ -708,7 +708,7 @@ public static void DefineUninitializedDataTest() methodIL.Emit(OpCodes.Ret); Type t = tb.CreateType(); - saveMethod.Invoke(ab, [file.Path]); + ab.Save(file.Path); TestAssemblyLoadContext tlc = new TestAssemblyLoadContext(); Assembly assemblyFromDisk = tlc.LoadFromAssemblyPath(file.Path); diff --git a/src/libraries/System.Reflection.Emit/tests/PersistableAssemblyBuilder/AssemblySaveTypeBuilderTests.cs b/src/libraries/System.Reflection.Emit/tests/PersistableAssemblyBuilder/AssemblySaveTypeBuilderTests.cs index 75be4000a7dd0a..bd510e83c65987 100644 --- a/src/libraries/System.Reflection.Emit/tests/PersistableAssemblyBuilder/AssemblySaveTypeBuilderTests.cs +++ b/src/libraries/System.Reflection.Emit/tests/PersistableAssemblyBuilder/AssemblySaveTypeBuilderTests.cs @@ -546,9 +546,9 @@ public void SaveMultipleGenericTypeParametersToEnsureSortingWorks() using (MetadataLoadContext mlc = new MetadataLoadContext(new CoreMetadataAssemblyResolver())) { Module m = mlc.LoadFromAssemblyPath(file.Path).Modules.First(); - Type[] type1Params = m.GetTypes()[2].GetGenericArguments(); + Type[] type1Params = m.GetTypes()[0].GetGenericArguments(); Type[] type2Params = m.GetTypes()[1].GetGenericArguments(); - Type[] type3Params = m.GetTypes()[0].GetGenericArguments(); + Type[] type3Params = m.GetTypes()[2].GetGenericArguments(); Assert.Equal("U", type1Params[0].Name); Assert.Empty(type1Params[0].GetTypeInfo().GetGenericParameterConstraints()); @@ -560,10 +560,10 @@ public void SaveMultipleGenericTypeParametersToEnsureSortingWorks() Assert.Equal("TOne", type3Params[0].Name); Assert.Equal(nameof(EmptyTestClass), type3Params[0].GetTypeInfo().GetGenericParameterConstraints()[0].Name); - Type[] method11Params = m.GetTypes()[2].GetMethod("TwoParameters").GetGenericArguments(); - Type[] method12Params = m.GetTypes()[2].GetMethod("FiveTypeParameters").GetGenericArguments(); + Type[] method11Params = m.GetTypes()[0].GetMethod("TwoParameters").GetGenericArguments(); + Type[] method12Params = m.GetTypes()[0].GetMethod("FiveTypeParameters").GetGenericArguments(); Assert.Equal(nameof(IMultipleMethod), method12Params[2].GetTypeInfo().GetGenericParameterConstraints()[0].Name); - Type[] method13Params = m.GetTypes()[2].GetMethod("OneParameter").GetGenericArguments(); + Type[] method13Params = m.GetTypes()[0].GetMethod("OneParameter").GetGenericArguments(); Type[] method21Params = m.GetTypes()[1].GetMethod("TestMethod").GetGenericArguments(); Assert.Equal("M", method11Params[0].Name);