if (m_inst != null)
throw new InvalidOperationException(SR.InvalidOperation_GenericParametersAlreadySet);
- for (int i = 0; i < names.Length; i++)
- ArgumentNullException.ThrowIfNull(names[i], nameof(names));
-
if (m_token != 0)
throw new InvalidOperationException(SR.InvalidOperation_MethodBuilderBaked);
- m_bIsGenMethDef = true;
m_inst = new RuntimeGenericTypeParameterBuilder[names.Length];
for (int i = 0; i < names.Length; i++)
- m_inst[i] = new RuntimeGenericTypeParameterBuilder(new RuntimeTypeBuilder(names[i], i, this));
+ {
+ string name = names[i];
+ ArgumentNullException.ThrowIfNull(name, nameof(names));
+ m_inst[i] = new RuntimeGenericTypeParameterBuilder(new RuntimeTypeBuilder(name, i, this));
+ }
+ m_bIsGenMethDef = true;
return m_inst;
}
}
}
- public override Type MakePointerType()
- {
- return SymbolType.FormCompoundType("*", this, 0)!;
- }
-
- public override Type MakeByRefType()
- {
- return SymbolType.FormCompoundType("&", this, 0)!;
- }
-
- [RequiresDynamicCode("The code for an array of the specified type might not be available.")]
- public override Type MakeArrayType()
- {
- return SymbolType.FormCompoundType("[]", this, 0)!;
- }
-
- [RequiresDynamicCode("The code for an array of the specified type might not be available.")]
- public override Type MakeArrayType(int rank)
- {
- string s = GetRankString(rank);
- return SymbolType.FormCompoundType(s, this, 0)!;
- }
-
#endregion
#region ICustomAttributeProvider Implementation
return m_inst;
}
- [RequiresDynamicCode("The native code for this instantiation might not be available at runtime.")]
- [RequiresUnreferencedCode("If some of the generic arguments are annotated (either with DynamicallyAccessedMembersAttribute, or generic constraints), trimming can't validate that the requirements of those annotations are met.")]
- public override Type MakeGenericType(params Type[] typeArguments)
- {
- return TypeBuilderInstantiation.MakeGenericType(this, typeArguments);
- }
-
public override Type[] GetGenericArguments() => m_inst ?? Type.EmptyTypes;
// If a TypeBuilder is generic, it must be a generic type definition
=> SetParentCore(parent);
protected abstract void SetParentCore([DynamicallyAccessedMembers(DynamicallyAccessedMemberTypes.All)] Type? parent);
+
+ public override Type MakePointerType()
+ {
+ return SymbolType.FormCompoundType("*", this, 0)!;
+ }
+
+ public override Type MakeByRefType()
+ {
+ return SymbolType.FormCompoundType("&", this, 0)!;
+ }
+
+ [RequiresDynamicCode("The code for an array of the specified type might not be available.")]
+ public override Type MakeArrayType()
+ {
+ return SymbolType.FormCompoundType("[]", this, 0)!;
+ }
+
+ [RequiresDynamicCode("The code for an array of the specified type might not be available.")]
+ public override Type MakeArrayType(int rank)
+ {
+ string s = GetRankString(rank);
+ return SymbolType.FormCompoundType(s, this, 0)!;
+ }
+
+ [RequiresDynamicCode("The native code for this instantiation might not be available at runtime.")]
+ [RequiresUnreferencedCode("If some of the generic arguments are annotated (either with DynamicallyAccessedMembersAttribute, or generic constraints), trimming can't validate that the requirements of those annotations are met.")]
+ public override Type MakeGenericType(params Type[] typeArguments)
+ {
+ return TypeBuilderInstantiation.MakeGenericType(this, typeArguments);
+ }
}
}
<data name="Argument_SizeConstMustBeSpecified" xml:space="preserve">
<value>SizeConst parameter must be specified for UnmanagedType.ByValTStr type.</value>
</data>
-</root>
+ <data name="InvalidOperation_GenericParametersAlreadySet" xml:space="preserve">
+ <value>The generic parameters are already defined on this MethodBuilder.</value>
+ </data>
+</root>
\ No newline at end of file
using System.Collections.Generic;
using System.Diagnostics.CodeAnalysis;
using System.Globalization;
+using System.Reflection.Metadata;
namespace System.Reflection.Emit
{
internal sealed class GenericTypeParameterBuilderImpl : GenericTypeParameterBuilder
{
private readonly string _name;
- private readonly TypeBuilderImpl _type;
+ private readonly TypeBuilder _type;
private readonly int _genParamPosition;
private GenericParameterAttributes _genParamAttributes;
- private bool _isGenericMethodParameter;
[DynamicallyAccessedMembers(DynamicallyAccessedMemberTypes.All)]
private Type? _parent;
internal List<CustomAttributeWrapper>? _customAttributes;
internal List<Type>? _interfaces;
+ private MethodBuilderImpl? _methodBuilder;
+ internal EntityHandle _parentHandle;
- internal GenericTypeParameterBuilderImpl(string name, int genParamPosition, TypeBuilderImpl typeBuilder)
+ internal GenericTypeParameterBuilderImpl(string name, int genParamPosition, TypeBuilderImpl typeBuilder, EntityHandle parentHandle)
{
_name = name;
_genParamPosition = genParamPosition;
_type = typeBuilder;
- _isGenericMethodParameter = false;
+ _parentHandle = parentHandle;
+ }
+
+ public GenericTypeParameterBuilderImpl(string name, int genParamPosition, MethodBuilderImpl methodBuilder)
+ {
+ _name = name;
+ _genParamPosition = genParamPosition;
+ _methodBuilder = methodBuilder;
+ _type = methodBuilder.DeclaringType;
}
protected override void SetBaseTypeConstraintCore([DynamicallyAccessedMembers(DynamicallyAccessedMemberTypes.All)] Type? baseTypeConstraint)
public override Type[] GetGenericParameterConstraints() =>
_interfaces == null ? EmptyTypes : _interfaces.ToArray();
- public override bool IsGenericTypeParameter => !_isGenericMethodParameter;
- public override bool IsGenericMethodParameter => _isGenericMethodParameter;
+ public override bool IsGenericTypeParameter => _methodBuilder is null;
+ public override bool IsGenericMethodParameter => _methodBuilder is not null;
public override int GenericParameterPosition => _genParamPosition;
public override GenericParameterAttributes GenericParameterAttributes => _genParamAttributes;
public override string Name => _name;
using System.Buffers.Binary;
using System.Collections.Generic;
-using System.Diagnostics;
using System.Diagnostics.CodeAnalysis;
using System.Globalization;
using System.Reflection.Metadata;
-using System.Runtime.InteropServices;
namespace System.Reflection.Emit
{
internal sealed class MethodBuilderImpl : MethodBuilder
{
- private readonly Type _returnType;
- private readonly Type[]? _parameterTypes;
+ private Type _returnType;
+ private Type[]? _parameterTypes;
private readonly ModuleBuilderImpl _module;
private readonly string _name;
private readonly CallingConventions _callingConventions;
private readonly TypeBuilderImpl _declaringType;
private MethodAttributes _attributes;
private MethodImplAttributes _methodImplFlags;
+ private GenericTypeParameterBuilderImpl[]? _typeParameters;
internal DllImportData? _dllImportData;
internal List<CustomAttributeWrapper>? _customAttributes;
_methodImplFlags = MethodImplAttributes.IL;
}
- internal BlobBuilder GetMethodSignatureBlob() =>
- MetadataSignatureHelper.MethodSignatureEncoder(_module, _parameterTypes, ReturnType, !IsStatic);
+ internal BlobBuilder GetMethodSignatureBlob() => MetadataSignatureHelper.MethodSignatureEncoder(_module,
+ _parameterTypes, ReturnType, GetSignatureConvention(_callingConventions), GetGenericArguments().Length, !IsStatic);
+ internal static SignatureCallingConvention GetSignatureConvention(CallingConventions callingConventions)
+ {
+ // TODO: find out and handle other SignatureCallingConvention scenarios
+ SignatureCallingConvention convention = SignatureCallingConvention.Default;
+ if ((callingConventions & CallingConventions.HasThis) != 0 ||
+ (callingConventions & CallingConventions.ExplicitThis) != 0)
+ {
+ convention |= SignatureCallingConvention.ThisCall;
+ }
+
+ if ((callingConventions & CallingConventions.VarArgs) != 0)
+ {
+ convention |= SignatureCallingConvention.VarArgs;
+ }
+
+ return convention;
+ }
protected override bool InitLocalsCore { get => throw new NotImplementedException(); set => throw new NotImplementedException(); }
- protected override GenericTypeParameterBuilder[] DefineGenericParametersCore(params string[] names) => throw new NotImplementedException();
+ protected override GenericTypeParameterBuilder[] DefineGenericParametersCore(params string[] names)
+ {
+ if (_typeParameters != null)
+ throw new InvalidOperationException(SR.InvalidOperation_GenericParametersAlreadySet);
+
+ var typeParameters = new GenericTypeParameterBuilderImpl[names.Length];
+ for (int i = 0; i < names.Length; i++)
+ {
+ string name = names[i];
+ ArgumentNullException.ThrowIfNull(names, nameof(names));
+ typeParameters[i] = new GenericTypeParameterBuilderImpl(name, i, this);
+ }
+
+ return _typeParameters = typeParameters;
+ }
+
protected override ParameterBuilder DefineParameterCore(int position, ParameterAttributes attributes, string? strParamName)
{
if (position > 0 && (_parameterTypes == null || position > _parameterTypes.Length))
_parameters[position] = parameter;
return parameter;
}
+
protected override ILGenerator GetILGeneratorCore(int size) => throw new NotImplementedException();
protected override void SetCustomAttributeCore(ConstructorInfo con, ReadOnlySpan<byte> binaryAttribute)
{
_methodImplFlags = attributes;
}
protected override void SetSignatureCore(Type? returnType, Type[]? returnTypeRequiredCustomModifiers, Type[]? returnTypeOptionalCustomModifiers, Type[]? parameterTypes,
- Type[][]? parameterTypeRequiredCustomModifiers, Type[][]? parameterTypeOptionalCustomModifiers) => throw new NotImplementedException();
+ Type[][]? parameterTypeRequiredCustomModifiers, Type[][]? parameterTypeOptionalCustomModifiers)
+ {
+ if (returnType != null)
+ {
+ _returnType = returnType;
+ }
+
+ if (parameterTypes != null)
+ {
+ _parameterTypes = new Type[parameterTypes.Length];
+ _parameters = new ParameterBuilderImpl[parameterTypes.Length + 1]; // parameter 0 reserved for return type
+ for (int i = 0; i < parameterTypes.Length; i++)
+ {
+ ArgumentNullException.ThrowIfNull(_parameterTypes[i] = parameterTypes[i], nameof(parameterTypes));
+ }
+ }
+ // TODO: Add support for other parameters: returnTypeRequiredCustomModifiers, returnTypeOptionalCustomModifiers, parameterTypeRequiredCustomModifiers and parameterTypeOptionalCustomModifiers
+ }
public override string Name => _name;
public override MethodAttributes Attributes => _attributes;
public override CallingConventions CallingConvention => _callingConventions;
public override TypeBuilder DeclaringType => _declaringType;
public override Module Module => _module;
- public override bool ContainsGenericParameters { get => throw new NotSupportedException(SR.NotSupported_DynamicModule); }
- public override bool IsGenericMethod { get => throw new NotImplementedException(); }
- public override bool IsGenericMethodDefinition { get => throw new NotImplementedException(); }
+ public override bool ContainsGenericParameters => throw new NotSupportedException();
+ public override bool IsGenericMethod => _typeParameters != null;
+ public override bool IsGenericMethodDefinition => _typeParameters != null;
public override bool IsSecurityCritical => true;
public override bool IsSecuritySafeCritical => false;
public override bool IsSecurityTransparent => false;
public override object[] GetCustomAttributes(Type attributeType, bool inherit) => throw new NotSupportedException(SR.NotSupported_DynamicModule);
- public override Type[] GetGenericArguments()
- => throw new NotImplementedException();
+ public override Type[] GetGenericArguments() => _typeParameters ?? Type.EmptyTypes;
- public override MethodInfo GetGenericMethodDefinition()
- => throw new NotImplementedException();
+ public override MethodInfo GetGenericMethodDefinition() => !IsGenericMethod ? throw new InvalidOperationException() : this;
public override int GetHashCode()
=> throw new NotImplementedException();
WriteCustomAttributes(_customAttributes, moduleHandle);
+ // All generic parameters for all types and methods should be written in specific order
+ List<GenericTypeParameterBuilderImpl> genericParams = new();
// Add each type definition to metadata table.
foreach (TypeBuilderImpl typeBuilder in _typeDefinitions)
{
if (typeBuilder.IsGenericType)
{
- foreach (GenericTypeParameterBuilderImpl gParam in typeBuilder.GenericTypeParameters)
+ foreach (GenericTypeParameterBuilderImpl param in typeBuilder.GenericTypeParameters)
{
- GenericParameterHandle handle = AddGenericTypeParameter(typeHandle, gParam);
- WriteCustomAttributes(gParam._customAttributes, handle);
-
- foreach (Type constraint in gParam.GetGenericParameterConstraints())
- {
- _metadataBuilder.AddGenericParameterConstraint(handle, GetTypeHandle(constraint));
- }
+ genericParams.Add(param);
}
}
}
WriteCustomAttributes(typeBuilder._customAttributes, typeHandle);
- WriteMethods(typeBuilder);
+ WriteMethods(typeBuilder, genericParams);
WriteFields(typeBuilder);
}
+
+ // Now write all generic parameters in order
+ genericParams.Sort((x, y) => {
+ int primary = CodedIndex.TypeOrMethodDef(x._parentHandle).CompareTo(CodedIndex.TypeOrMethodDef(y._parentHandle));
+ if (primary != 0)
+ return primary;
+
+ return x.GenericParameterPosition.CompareTo(y.GenericParameterPosition);
+ });
+
+ foreach (GenericTypeParameterBuilderImpl param in genericParams)
+ {
+ AddGenericTypeParametersAndConstraintsCustomAttributes(param._parentHandle, param);
+ }
}
- private void WriteMethods(TypeBuilderImpl typeBuilder)
+ private void WriteMethods(TypeBuilderImpl typeBuilder, List<GenericTypeParameterBuilderImpl> genericParams)
{
foreach (MethodBuilderImpl method in typeBuilder._methodDefinitions)
{
WriteCustomAttributes(method._customAttributes, methodHandle);
_nextMethodDefRowId++;
+ if (method.IsGenericMethodDefinition)
+ {
+ Type[] gParams = method.GetGenericArguments();
+ for (int i = 0; i < gParams.Length; i++)
+ {
+ GenericTypeParameterBuilderImpl param = (GenericTypeParameterBuilderImpl)gParams[i];
+ param._parentHandle = methodHandle;
+ genericParams.Add(param);
+ }
+ }
+
if (method._parameters != null)
{
foreach (ParameterBuilderImpl parameter in method._parameters)
return handle;
}
- private GenericParameterHandle AddGenericTypeParameter(TypeDefinitionHandle typeHandle, GenericTypeParameterBuilderImpl gParam) =>
- _metadataBuilder.AddGenericParameter(
- parent: typeHandle,
+ private void AddGenericTypeParametersAndConstraintsCustomAttributes(EntityHandle parentHandle, GenericTypeParameterBuilderImpl gParam)
+ {
+ GenericParameterHandle handle = _metadataBuilder.AddGenericParameter(
+ parent: parentHandle,
attributes: gParam.GenericParameterAttributes,
name: _metadataBuilder.GetOrAddString(gParam.Name),
index: gParam.GenericParameterPosition);
+ WriteCustomAttributes(gParam._customAttributes, handle);
+ foreach (Type constraint in gParam.GetGenericParameterConstraints())
+ {
+ _metadataBuilder.AddGenericParameterConstraint(handle, GetTypeHandle(constraint));
+ }
+ }
+
private void AddDefaultValue(ParameterHandle parameterHandle, object? defaultValue) =>
_metadataBuilder.AddConstant(parent: parameterHandle, value: defaultValue);
// 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.Immutable;
using System.Reflection.Metadata;
using System.Reflection.Metadata.Ecma335;
internal static BlobBuilder FieldSignatureEncoder(Type fieldType, ModuleBuilderImpl module)
{
BlobBuilder fieldSignature = new();
-
- WriteSignatureForType(new BlobEncoder(fieldSignature).FieldSignature(), fieldType, module);
+ WriteSignatureForType(new BlobEncoder(fieldSignature).Field().Type(), fieldType, module);
return fieldSignature;
}
return constructorSignature;
}
- internal static BlobBuilder MethodSignatureEncoder(ModuleBuilderImpl module, Type[]? parameters, Type? returnType, bool isInstance)
+ internal static BlobBuilder MethodSignatureEncoder(ModuleBuilderImpl module, Type[]? parameters,
+ Type? returnType, SignatureCallingConvention convention, int genParamCount, bool isInstance)
{
// Encoding return type and parameters.
BlobBuilder methodSignature = new();
new BlobEncoder(methodSignature).
- MethodSignature(isInstanceMethod: isInstance).
+ MethodSignature(convention: convention, genericParameterCount: genParamCount, isInstanceMethod: isInstance).
Parameters((parameters == null) ? 0 : parameters.Length, out ReturnTypeEncoder retEncoder, out ParametersEncoder parEncoder);
if (returnType != null && returnType != module.GetTypeFromCoreAssembly(CoreTypeId.Void))
private static void WriteSignatureForType(SignatureTypeEncoder signature, Type type, ModuleBuilderImpl module)
{
+ if (type.IsArray)
+ {
+ Type elementType = type.GetElementType()!;
+ int rank = type.GetArrayRank();
+ if (rank == 1)
+ {
+ WriteSignatureForType(signature.SZArray(), elementType, module);
+ }
+ else
+ {
+ signature.Array(out SignatureTypeEncoder elTypeSignature, out ArrayShapeEncoder arrayEncoder);
+ WriteSimpleSignature(elTypeSignature, elementType, module);
+ arrayEncoder.Shape(type.GetArrayRank(), ImmutableArray.Create<int>(), ImmutableArray.Create<int>(new int[rank]));
+ }
+ }
+ else if (type.IsPointer)
+ {
+ WriteSignatureForType(signature.Pointer(), type.GetElementType()!, module);
+ }
+ else if (type.IsByRef)
+ {
+ signature.Builder.WriteByte((byte)SignatureTypeCode.ByReference);
+ WriteSignatureForType(signature, type.GetElementType()!, module);
+ }
+ else if (type.IsGenericType)
+ {
+ Type[] genericArguments = type.GetGenericArguments();
+
+ GenericTypeArgumentsEncoder encoder = signature.GenericInstantiation(
+ module.GetTypeHandle(type.GetGenericTypeDefinition()), genericArguments.Length, type.IsValueType);
+ foreach (Type gType in genericArguments)
+ {
+ if (gType.IsGenericMethodParameter)
+ {
+ encoder.AddArgument().GenericMethodTypeParameter(gType.GenericParameterPosition);
+ }
+ else if (gType.IsGenericParameter)
+ {
+ encoder.AddArgument().GenericTypeParameter(gType.GenericParameterPosition);
+ }
+ else
+ {
+ WriteSignatureForType(encoder.AddArgument(), gType, module);
+ }
+ }
+ }
+ else if (type.IsGenericMethodParameter)
+ {
+ signature.GenericMethodTypeParameter(type.GenericParameterPosition);
+ }
+ else if (type.IsGenericParameter)
+ {
+ signature.GenericTypeParameter(type.GenericParameterPosition);
+ }
+ else
+ {
+ WriteSimpleSignature(signature, type, module);
+ }
+ }
+
+ private static void WriteSimpleSignature(SignatureTypeEncoder signature, Type type, ModuleBuilderImpl module)
+ {
CoreTypeId? typeId = module.GetTypeIdFromCoreTypes(type);
switch (typeId)
{
+ case CoreTypeId.Void:
+ signature.Builder.WriteByte((byte)SignatureTypeCode.Void);
+ return;
case CoreTypeId.Boolean:
signature.Boolean();
return;
signature.String();
return;
case CoreTypeId.TypedReference:
- signature.Builder.WriteByte((byte)SignatureTypeCode.TypedReference);
+ signature.TypedReference();
return;
}
if (_typeParameters != null)
throw new InvalidOperationException();
- _typeParameters = new GenericTypeParameterBuilderImpl[names.Length];
-
+ var typeParameters = new GenericTypeParameterBuilderImpl[names.Length];
for (int i = 0; i < names.Length; i++)
{
string name = names[i];
ArgumentNullException.ThrowIfNull(name, nameof(names));
- _typeParameters[i] = new GenericTypeParameterBuilderImpl(name, i, this);
+ typeParameters[i] = new GenericTypeParameterBuilderImpl(name, i, this, _handle);
}
- return _typeParameters;
+ return _typeParameters = typeParameters;
}
protected override FieldBuilder DefineInitializedDataCore(string name, byte[] data, FieldAttributes attributes) => throw new NotImplementedException();
=> throw new NotSupportedException();
[DynamicallyAccessedMembers(GetAllMembers)]
public override MemberInfo[] GetMembers(BindingFlags bindingAttr) => throw new NotSupportedException();
-
public override bool IsAssignableFrom([NotNullWhen(true)] Type? c) => throw new NotSupportedException();
- public override Type MakePointerType() => throw new NotSupportedException();
- public override Type MakeByRefType() => throw new NotSupportedException();
- [RequiresDynamicCode("The code for an array of the specified type might not be available.")]
- public override Type MakeArrayType() => throw new NotSupportedException();
- [RequiresDynamicCode("The code for an array of the specified type might not be available.")]
- public override Type MakeArrayType(int rank) => throw new NotSupportedException();
internal const DynamicallyAccessedMemberTypes GetAllMembers = DynamicallyAccessedMemberTypes.PublicFields | DynamicallyAccessedMemberTypes.NonPublicFields |
DynamicallyAccessedMemberTypes.PublicMethods | DynamicallyAccessedMemberTypes.NonPublicMethods |
// 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;
using System.Collections.Generic;
using System.Diagnostics.CodeAnalysis;
using System.IO;
{
using (TempFile file = TempFile.Create())
{
- AssemblyBuilder assemblyBuilder = AssemblyTools.PopulateAssemblyBuilderAndSaveMethod(
- s_assemblyName, null, typeof(string), out MethodInfo saveMethod);
- ModuleBuilder mb = assemblyBuilder.DefineDynamicModule("My Module");
- TypeBuilder tb = mb.DefineType("TestInterface", TypeAttributes.Interface | TypeAttributes.Abstract);
+ TypeBuilder tb = CreateAssemblyAndDefineType(out AssemblyBuilder assemblyBuilder, out MethodInfo saveMethod);
tb.DefineMethod("TestMethod", MethodAttributes.Public);
-
saveMethod.Invoke(assemblyBuilder, new object[] { file.Path });
Assembly assemblyFromDisk = AssemblyTools.LoadAssemblyFromPath(file.Path);
Module moduleFromDisk = assemblyFromDisk.Modules.First();
- Assert.Equal("My Module", moduleFromDisk.ScopeName);
+ Assert.Equal("MyModule", moduleFromDisk.ScopeName);
Assert.Equal(1, moduleFromDisk.GetTypes().Length);
Type testType = moduleFromDisk.GetTypes()[0];
}
}
+ private static TypeBuilder CreateAssemblyAndDefineType(out AssemblyBuilder assemblyBuilder, out MethodInfo saveMethod)
+ {
+ assemblyBuilder = AssemblyTools.PopulateAssemblyBuilderAndSaveMethod(s_assemblyName, null, typeof(string), out saveMethod);
+ return assemblyBuilder.DefineDynamicModule("MyModule")
+ .DefineType("TestInterface", TypeAttributes.Interface | TypeAttributes.Abstract);
+ }
+
[Fact]
public void AddInterfaceImplementationTest()
{
}
}
- [Fact]
- public void SaveGenericTypeParametersForAType()
+ public static IEnumerable<object[]> TypeParameters()
+ {
+ yield return new object[] { new string[] { "TFirst", "TSecond", "TThird" } };
+ yield return new object[] { new string[] { "TFirst" } };
+ }
+
+ [Theory]
+ [MemberData(nameof(TypeParameters))]
+ public void SaveGenericTypeParametersForAType(string[] typeParamNames)
{
using (TempFile file = TempFile.Create())
{
- AssemblyBuilder assemblyBuilder = AssemblyTools.PopulateAssemblyBuilderAndSaveMethod(
- s_assemblyName, null, typeof(string), out MethodInfo saveMethod);
- ModuleBuilder mb = assemblyBuilder.DefineDynamicModule("My Module");
- TypeBuilder tb = mb.DefineType("TestInterface", TypeAttributes.Interface | TypeAttributes.Abstract);
- string[] typeParamNames = new string[] { "TFirst", "TSecond", "TThird" };
+ TypeBuilder tb = CreateAssemblyAndDefineType(out AssemblyBuilder assemblyBuilder, out MethodInfo saveMethod);
+ MethodBuilder method = tb.DefineMethod("TestMethod", MethodAttributes.Public);
GenericTypeParameterBuilder[] typeParams = tb.DefineGenericParameters(typeParamNames);
- typeParams[0].SetInterfaceConstraints(new Type[] { typeof(IAccess), typeof(INoMethod)});
- typeParams[1].SetCustomAttribute(new CustomAttributeBuilder(typeof(DynamicallyAccessedMembersAttribute).GetConstructor(
- new Type[] { typeof(DynamicallyAccessedMemberTypes) }), new object[] { DynamicallyAccessedMemberTypes.PublicProperties }));
- typeParams[2].SetBaseTypeConstraint(typeof(EmptyTestClass));
- typeParams[2].SetGenericParameterAttributes(GenericParameterAttributes.VarianceMask);
+ if (typeParams.Length > 2)
+ {
+ SetVariousGenericParameterValues(typeParams);
+ }
saveMethod.Invoke(assemblyBuilder, new object[] { file.Path });
- Assembly assemblyFromDisk = AssemblyTools.LoadAssemblyFromPath(file.Path);
- Type testType = assemblyFromDisk.Modules.First().GetTypes()[0];
+ Type testType = AssemblyTools.LoadAssemblyFromPath(file.Path).Modules.First().GetTypes()[0];
+ MethodInfo testMethod = testType.GetMethod("TestMethod");
Type[] genericTypeParams = testType.GetGenericArguments();
-
- Assert.Equal(3, genericTypeParams.Length);
- Assert.Equal("TFirst", genericTypeParams[0].Name);
+
+ 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[1].SetCustomAttribute(new CustomAttributeBuilder(typeof(DynamicallyAccessedMembersAttribute).GetConstructor(
+ new Type[] { typeof(DynamicallyAccessedMemberTypes) }), new object[] { DynamicallyAccessedMemberTypes.PublicProperties }));
+ typeParams[2].SetBaseTypeConstraint(typeof(EmptyTestClass));
+ typeParams[2].SetGenericParameterAttributes(GenericParameterAttributes.VarianceMask);
+ }
+
+ private static void AssertGenericParameters(GenericTypeParameterBuilder[] typeParams, Type[] genericTypeParams)
+ {
+ Assert.Equal("TFirst", genericTypeParams[0].Name);
+ if (typeParams.Length > 2)
+ {
Assert.Equal("TSecond", genericTypeParams[1].Name);
Assert.Equal("TThird", genericTypeParams[2].Name);
-
Type[] constraints = genericTypeParams[0].GetTypeInfo().GetGenericParameterConstraints();
Assert.Equal(2, constraints.Length);
Assert.Equal(typeof(IAccess).FullName, constraints[0].FullName);
Assert.Equal(typeof(EmptyTestClass).FullName, constraints2[0].FullName);
Assert.Equal(GenericParameterAttributes.None, genericTypeParams[0].GenericParameterAttributes);
Assert.Equal(GenericParameterAttributes.VarianceMask, genericTypeParams[2].GenericParameterAttributes);
-
IList<CustomAttributeData> attributes = genericTypeParams[1].GetCustomAttributesData();
Assert.Equal(1, attributes.Count);
Assert.Equal("DynamicallyAccessedMembersAttribute", attributes[0].AttributeType.Name);
Assert.Empty(genericTypeParams[0].GetCustomAttributesData());
}
}
+
+ [Theory]
+ [MemberData(nameof(TypeParameters))]
+ public void SaveGenericTypeParametersForAMethod(string[] typeParamNames)
+ {
+ using (TempFile file = TempFile.Create())
+ {
+ TypeBuilder tb = CreateAssemblyAndDefineType(out AssemblyBuilder assemblyBuilder, out MethodInfo saveMethod);
+ MethodBuilder method = tb.DefineMethod("TestMethod", MethodAttributes.Public);
+ GenericTypeParameterBuilder[] typeParams = method.DefineGenericParameters(typeParamNames);
+ if (typeParams.Length > 2)
+ {
+ SetVariousGenericParameterValues(typeParams);
+ }
+ saveMethod.Invoke(assemblyBuilder, new object[] { file.Path });
+
+ Type testType = AssemblyTools.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);
+ }
+ }
+
+ [Theory]
+ [InlineData(0, "TestInterface[]")]
+ [InlineData(1, "TestInterface[]")] // not [*]
+ [InlineData(2, "TestInterface[,]")]
+ [InlineData(3, "TestInterface[,,]")]
+ public void SaveArrayTypeSignature(int rank, string name)
+ {
+ using (TempFile file = TempFile.Create())
+ {
+ TypeBuilder tb = CreateAssemblyAndDefineType(out AssemblyBuilder assemblyBuilder, out MethodInfo saveMethod);
+ 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[,,,]) });
+ saveMethod.Invoke(assemblyBuilder, new object[] { file.Path });
+
+ Type testType = AssemblyTools.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);
+ }
+ }
+
+ private static void AssertArrayTypeSignature(int rank, string name, Type arrayType)
+ {
+ Assert.True(rank < 2 ? arrayType.IsSZArray : arrayType.IsArray);
+ rank = rank == 0 ? rank + 1 : rank;
+ Assert.Equal(rank, arrayType.GetArrayRank());
+ Assert.Equal(name, arrayType.Name);
+ }
+
+ [Fact]
+ public void SaveByRefTypeSignature()
+ {
+ using (TempFile file = TempFile.Create())
+ {
+ TypeBuilder tb = CreateAssemblyAndDefineType(out AssemblyBuilder assemblyBuilder, out MethodInfo saveMethod);
+ Type byrefType = tb.MakeByRefType();
+ MethodBuilder mb = tb.DefineMethod("TestMethod", MethodAttributes.Public);
+ mb.SetReturnType(byrefType);
+ mb.SetParameters(new Type[] { typeof(INoMethod), byrefType });
+ saveMethod.Invoke(assemblyBuilder, new object[] { file.Path });
+
+ Type testType = AssemblyTools.LoadAssemblyFromPath(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);
+ }
+ }
+
+ private static void AssertByRefType(Type byrefParam)
+ {
+ Assert.True(byrefParam.IsByRef);
+ Assert.Equal("TestInterface&", byrefParam.Name);
+ }
+
+ [Fact]
+ public void SavePointerTypeSignature()
+ {
+ using (TempFile file = TempFile.Create())
+ {
+ TypeBuilder tb = CreateAssemblyAndDefineType(out AssemblyBuilder assemblyBuilder, out MethodInfo saveMethod);
+ Type pointerType = tb.MakePointerType();
+ MethodBuilder mb = tb.DefineMethod("TestMethod", MethodAttributes.Public);
+ mb.SetReturnType(pointerType);
+ mb.SetParameters(new Type[] { typeof(INoMethod), pointerType });
+ saveMethod.Invoke(assemblyBuilder, new object[] { file.Path });
+
+ Type testType = AssemblyTools.LoadAssemblyFromPath(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);
+ }
+ }
+
+ private void AssertPointerType(Type testType)
+ {
+ Assert.True(testType.IsPointer);
+ Assert.Equal("TestInterface*", testType.Name);
+ }
+
+ public static IEnumerable<object[]> SaveGenericType_TestData()
+ {
+ yield return new object[] { new string[] { "U", "T" }, new Type[] { typeof(string), typeof(int) }, "TestInterface[System.String,System.Int32]" };
+ yield return new object[] { new string[] { "U", "T" }, new Type[] { typeof(MakeGenericTypeClass), typeof(MakeGenericTypeInterface) },
+ "TestInterface[System.Reflection.Emit.Tests.MakeGenericTypeClass,System.Reflection.Emit.Tests.MakeGenericTypeInterface]" };
+ yield return new object[] { new string[] { "U" }, new Type[] { typeof(List<string>) }, "TestInterface[System.Collections.Generic.List`1[System.String]]" };
+ }
+
+ [Theory]
+ [MemberData(nameof(SaveGenericType_TestData))]
+ public void SaveGenericTypeSignature(string[] genericParams, Type[] typeArguments, string stringRepresentation)
+ {
+ using (TempFile file = TempFile.Create())
+ {
+ TypeBuilder tb = CreateAssemblyAndDefineType(out AssemblyBuilder assemblyBuilder, out MethodInfo saveMethod);
+ 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 });
+ saveMethod.Invoke(assemblyBuilder, new object[] { file.Path });
+
+ Type testType = AssemblyTools.LoadAssemblyFromPath(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);
+ }
+ }
+
+ private static void AssertGenericType(string stringRepresentation, Type paramType)
+ {
+ Assert.True(paramType.IsGenericType);
+ Assert.Equal(stringRepresentation, paramType.ToString());
+ Assert.False(paramType.IsGenericParameter);
+ Assert.False(paramType.IsGenericTypeDefinition);
+ Assert.False(paramType.IsGenericTypeParameter);
+ Assert.False(paramType.IsGenericMethodParameter);
+ }
+
+ [Fact]
+ 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" });
+ MethodBuilder mb = tb.DefineMethod("TestMethod", MethodAttributes.Public);
+ GenericTypeParameterBuilder[] methodParams = mb.DefineGenericParameters(new string[] { "M", "N" });
+ Type genericType = tb.MakeGenericType(typeParams);
+ mb.SetReturnType(methodParams[0]);
+ mb.SetParameters(new Type[] { typeof(INoMethod), genericType, typeParams[1] });
+ saveMethod.Invoke(assemblyBuilder, new object[] { file.Path });
+
+ Type testType = AssemblyTools.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);
+ }
+ }
+
+ [Fact]
+ public void SaveMultipleGenericTypeParametersToEnsureSortingWorks()
+ {
+ using (TempFile file = TempFile.Create())
+ {
+ AssemblyBuilder assemblyBuilder = AssemblyTools.PopulateAssemblyBuilderAndSaveMethod(
+ s_assemblyName, null, typeof(string), out MethodInfo saveMethod);
+ 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 Type[] { 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" });
+ GenericTypeParameterBuilder[] methodParams = m12.DefineGenericParameters(new string[] { "A", "B", "C", "D", "F" });
+ methodParams[2].SetInterfaceConstraints(new Type[] { typeof(IMultipleMethod) });
+ m13.DefineGenericParameters(new string[] { "T" });
+ TypeBuilder tb2 = mb.DefineType("TestInterface2", TypeAttributes.Interface | TypeAttributes.Abstract);
+ tb2.DefineGenericParameters(new string[] { "TFirst", "TSecond", "TThird" });
+ MethodBuilder m21 = tb2.DefineMethod("TestMethod", MethodAttributes.Public);
+ m21.DefineGenericParameters(new string[] { "X", "Y", "Z" });
+ TypeBuilder tb3 = mb.DefineType("TestType");
+ GenericTypeParameterBuilder[] typePar = tb3.DefineGenericParameters(new string[] { "TOne" });
+ typePar[0].SetBaseTypeConstraint(typeof(EmptyTestClass));
+ saveMethod.Invoke(assemblyBuilder, new object[] { file.Path });
+
+ Module m = AssemblyTools.LoadAssemblyFromPath(file.Path).Modules.First();
+ Type[] type1Params = m.GetTypes()[0].GetGenericArguments();
+ Type[] type2Params = m.GetTypes()[1].GetGenericArguments();
+ Type[] type3Params = m.GetTypes()[2].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()[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()[0].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);
+ }
+ }
}
// Test Types
}
}
- [RequiresDynamicCode("The code for an array of the specified type might not be available.")]
- public override Type MakeArrayType()
- {
- return SymbolType.FormCompoundType("[]", this, 0)!;
- }
-
- [RequiresDynamicCode("The code for an array of the specified type might not be available.")]
- public override Type MakeArrayType(int rank)
- {
- string s = GetRankString(rank);
- return SymbolType.FormCompoundType(s, this, 0)!;
- }
-
- public override Type MakeByRefType()
- {
- return SymbolType.FormCompoundType("&", this, 0)!;
- }
-
[RequiresDynamicCode("The native code for this instantiation might not be available at runtime.")]
[RequiresUnreferencedCode("If some of the generic arguments are annotated (either with DynamicallyAccessedMembersAttribute, or generic constraints), trimming can't validate that the requirements of those annotations are met.")]
public override Type MakeGenericType(params Type[] typeArguments)
return RuntimeAssemblyBuilder.MakeGenericType(this, copy);
}
- public override Type MakePointerType()
- {
- return SymbolType.FormCompoundType("*", this, 0)!;
- }
-
public override RuntimeTypeHandle TypeHandle
{
get