File: System\Reflection\TypeLoading\Types\RoModifiedType.cs
Web Access
Project: src\src\libraries\System.Reflection.MetadataLoadContext\src\System.Reflection.MetadataLoadContext.csproj (System.Reflection.MetadataLoadContext)
// 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;
using System.Diagnostics.CodeAnalysis;
using System.Reflection.TypeLoading;
using StructLayoutAttribute = System.Runtime.InteropServices.StructLayoutAttribute;
 
namespace System.Reflection
{
    /// <summary>
    /// Base type for modified types obtained through FieldInfo.GetModifiedFieldInfo(), PropertyInfo.GetModifiedPropertyInfo()
    /// and ParameterInfo.GetModifiedParameterInfo().
    /// </summary>
    internal abstract class RoModifiedType : RoType
    {
        private List<Type>? _requiredModifiersBuilder;
        private List<Type>? _optionalModifiersBuilder;
        private Type[]? _requiredModifiers;
        private Type[]? _optionalModifiers;
        private readonly RoType _unmodifiedType;
 
        protected RoModifiedType(RoType unmodifiedType)
        {
            _unmodifiedType = unmodifiedType;
        }
 
        public static RoModifiedType Create(RoType unmodifiedType)
        {
            RoModifiedType modifiedType;
 
            if (unmodifiedType is RoModifiedType mod)
            {
                // A nested type, such as a function pointer in 'delegate*<void>[]' array, may already be modified.
                modifiedType = mod;
            }
            else if (unmodifiedType.IsFunctionPointer)
            {
                modifiedType = new RoModifiedFunctionPointerType((RoFunctionPointerType)unmodifiedType);
            }
            else if (unmodifiedType.IsGenericType)
            {
                modifiedType = new RoModifiedGenericType((RoConstructedGenericType)unmodifiedType);
            }
            else if (unmodifiedType.HasElementType)
            {
                modifiedType = new RoModifiedHasElementType(unmodifiedType);
            }
            else
            {
                modifiedType = new RoModifiedStandaloneType(unmodifiedType);
            }
 
            return modifiedType;
        }
 
        public void AddRequiredModifier(Type type)
        {
            Debug.Assert(_requiredModifiers == null);
            _requiredModifiersBuilder ??= new List<Type>();
            _requiredModifiersBuilder.Add(type);
        }
 
        public void AddOptionalModifier(Type type)
        {
            Debug.Assert(_optionalModifiers == null);
            _optionalModifiersBuilder ??= new List<Type>();
            _optionalModifiersBuilder.Add(type);
        }
 
        // Below are the multitude of Type overloads. We throw NSE for members that would return an unmodified Type
        // directly or indirectly. We do this in case we want to support returning modified types instead.
 
        public override Type[] GetRequiredCustomModifiers()
        {
            if (_requiredModifiers == null)
            {
                if (_requiredModifiersBuilder == null)
                {
                    _requiredModifiers = EmptyTypes;
                }
                else
                {
                    _requiredModifiers = _requiredModifiersBuilder.ToArray();
                    _requiredModifiersBuilder = null;
                }
            }
 
            return Helpers.CloneArray(_requiredModifiers);
        }
 
        public override Type[] GetOptionalCustomModifiers()
        {
            if (_optionalModifiers == null)
            {
                if (_optionalModifiersBuilder == null)
                {
                    _optionalModifiers = EmptyTypes;
                }
                else
                {
                    _optionalModifiers = _optionalModifiersBuilder.ToArray();
                    _optionalModifiersBuilder = null;
                }
            }
 
            return Helpers.CloneArray(_optionalModifiers);
        }
 
        public override Type UnderlyingSystemType => _unmodifiedType;
 
        // Modified types do not support Equals. That would need to include custom modifiers and any parameterized types recursively.
        // UnderlyingSystemType.Equals() should should be used if basic equality is necessary.
        public override bool Equals([NotNullWhen(true)] object? obj) => throw new NotSupportedException(SR.NotSupported_ModifiedType);
        public override bool Equals(Type? other) => throw new NotSupportedException(SR.NotSupported_ModifiedType);
        public override int GetHashCode() => throw new NotSupportedException(SR.NotSupported_ModifiedType);
 
        public override string ToString() => _unmodifiedType.ToString();
        public sealed override bool IsEnum => _unmodifiedType.IsEnum;
        protected sealed override bool IsPrimitiveImpl() => _unmodifiedType.IsPrimitive;
        protected sealed override bool IsValueTypeImpl() => _unmodifiedType.IsValueType;
        public override bool IsTypeDefinition => _unmodifiedType.IsTypeDefinition;
        public override bool IsGenericTypeDefinition => _unmodifiedType.IsGenericTypeDefinition;
        protected override bool HasElementTypeImpl() => _unmodifiedType.Call_HasElementTypeImpl();
        protected override bool IsArrayImpl() => _unmodifiedType.Call_IsArrayImpl();
        public override bool IsSZArray => _unmodifiedType.IsSZArray();
        public override bool IsVariableBoundArray => _unmodifiedType.IsVariableBoundArray;
        protected override bool IsByRefImpl() => _unmodifiedType.Call_IsByRefImpl();
        protected override bool IsPointerImpl() => _unmodifiedType.Call_IsPointerImpl();
        public override bool IsFunctionPointer => _unmodifiedType.IsFunctionPointer;
        public override bool IsUnmanagedFunctionPointer => _unmodifiedType.IsUnmanagedFunctionPointer;
        public override bool IsConstructedGenericType => _unmodifiedType.IsConstructedGenericType;
        public override bool IsGenericParameter => _unmodifiedType.IsGenericParameter;
        public override bool IsGenericTypeParameter => _unmodifiedType.IsGenericTypeParameter;
        public override bool IsGenericMethodParameter => _unmodifiedType.IsGenericMethodParameter;
        public override bool ContainsGenericParameters => _unmodifiedType.ContainsGenericParameters;
 
        internal override RoModule GetRoModule() => _unmodifiedType.GetRoModule();
 
        public override int GetArrayRank() => _unmodifiedType.GetArrayRank();
 
        protected override string ComputeName() => _unmodifiedType.Call_ComputeName();
        protected override string? ComputeNamespace() => _unmodifiedType.Call_ComputeNamespace();
        protected override string? ComputeFullName() => _unmodifiedType.Call_ComputeFullName();
 
        protected override TypeAttributes ComputeAttributeFlags() => _unmodifiedType.Call_ComputeAttributeFlags();
        protected override TypeCode GetTypeCodeImpl() => _unmodifiedType.Call_GetTypeCodeImpl();
 
        public override MethodBase? DeclaringMethod => throw new NotSupportedException(SR.NotSupported_ModifiedType);
        protected override RoType? ComputeDeclaringType() => throw new NotSupportedException(SR.NotSupported_ModifiedType);
 
        public override IEnumerable<TypeInfo> DeclaredNestedTypes
        {
#if NET
            [DynamicallyAccessedMembers(DynamicallyAccessedMemberTypes.NonPublicNestedTypes | DynamicallyAccessedMemberTypes.PublicNestedTypes)]
#endif
            get { throw new NotSupportedException(SR.NotSupported_ModifiedType); }
        }
 
        public override IEnumerable<CustomAttributeData> CustomAttributes => _unmodifiedType.CustomAttributes;
        internal override bool IsCustomAttributeDefined(ReadOnlySpan<byte> ns, ReadOnlySpan<byte> name) => _unmodifiedType.IsCustomAttributeDefined(ns, name);
        internal override CustomAttributeData? TryFindCustomAttribute(ReadOnlySpan<byte> ns, ReadOnlySpan<byte> name) => _unmodifiedType.TryFindCustomAttribute(ns, name);
 
        public override int MetadataToken => throw new NotSupportedException(SR.NotSupported_ModifiedType);
 
        internal override RoType? GetRoElementType() => null;
 
        public override Type GetGenericTypeDefinition() => throw new NotSupportedException(SR.NotSupported_ModifiedType);
 
        // Generic parameters are supported.
        internal override RoType[] GetGenericTypeParametersNoCopy() => _unmodifiedType.GetGenericTypeParametersNoCopy();
        internal override RoType[] GetGenericTypeArgumentsNoCopy() => _unmodifiedType.GetGenericTypeArgumentsNoCopy();
        protected internal override RoType[] GetGenericArgumentsNoCopy() => _unmodifiedType.GetGenericArgumentsNoCopy();
        [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) => throw new NotSupportedException(SR.NotSupported_ModifiedType);
 
        public override Type GetFunctionPointerReturnType() => throw new InvalidOperationException(SR.InvalidOperation_NotFunctionPointer);
        public override Type[] GetFunctionPointerParameterTypes() => throw new InvalidOperationException(SR.InvalidOperation_NotFunctionPointer);
 
        public override GenericParameterAttributes GenericParameterAttributes => _unmodifiedType.GenericParameterAttributes;
        public override int GenericParameterPosition => _unmodifiedType.GenericParameterPosition;
        public override Type[] GetGenericParameterConstraints() => throw new NotSupportedException(SR.NotSupported_ModifiedType);
        public override Guid GUID => _unmodifiedType.GUID;
        public override StructLayoutAttribute? StructLayoutAttribute => _unmodifiedType.StructLayoutAttribute;
        protected internal override RoType ComputeEnumUnderlyingType() => throw new NotSupportedException(SR.NotSupported_ModifiedType);
 
        internal override RoType? ComputeBaseTypeWithoutDesktopQuirk() => throw new NotSupportedException(SR.NotSupported_ModifiedType);
        internal override IEnumerable<RoType> ComputeDirectlyImplementedInterfaces() => throw new NotSupportedException(SR.NotSupported_ModifiedType);
 
        // Low level support for the BindingFlag-driven enumerator apis.
        internal override IEnumerable<ConstructorInfo> GetConstructorsCore(NameFilter? filter) => throw new NotSupportedException(SR.NotSupported_ModifiedType);
        internal override IEnumerable<MethodInfo> GetMethodsCore(NameFilter? filter, Type reflectedType) => throw new NotSupportedException(SR.NotSupported_ModifiedType);
        internal override IEnumerable<EventInfo> GetEventsCore(NameFilter? filter, Type reflectedType) => throw new NotSupportedException(SR.NotSupported_ModifiedType);
        internal override IEnumerable<FieldInfo> GetFieldsCore(NameFilter? filter, Type reflectedType) => throw new NotSupportedException(SR.NotSupported_ModifiedType);
        internal override IEnumerable<PropertyInfo> GetPropertiesCore(NameFilter? filter, Type reflectedType) => throw new NotSupportedException(SR.NotSupported_ModifiedType);
        internal override IEnumerable<RoType> GetNestedTypesCore(NameFilter? filter) => throw new NotSupportedException(SR.NotSupported_ModifiedType);
    }
}