File: System\Reflection\TypeLoading\Types\Ecma\EcmaDefinitionType.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.Reflection.Metadata;
 
namespace System.Reflection.TypeLoading.Ecma
{
    /// <summary>
    /// RoTypes that return true for IsTypeDefinition and get its metadata from a PEReader.
    /// </summary>
    internal sealed partial class EcmaDefinitionType : RoDefinitionType
    {
        private readonly EcmaModule _module;
        private readonly TypeDefinitionHandle _handle;
 
        internal EcmaDefinitionType(TypeDefinitionHandle handle, EcmaModule module)
            : base()
        {
            Debug.Assert(module != null);
            Debug.Assert(!handle.IsNil);
 
            _module = module;
            _handle = handle;
            _neverAccessThisExceptThroughTypeDefinitionProperty = handle.GetTypeDefinition(Reader);
        }
 
        internal sealed override RoModule GetRoModule() => _module;
        internal EcmaModule GetEcmaModule() => _module;
 
        protected sealed override RoType? ComputeDeclaringType()
        {
            if (!TypeDefinition.IsNested)
                return null;
 
            return TypeDefinition.GetDeclaringType().ResolveTypeDef(GetEcmaModule());
        }
 
        protected sealed override string ComputeName() => TypeDefinition.Name.GetString(Reader).EscapeTypeNameIdentifier();
 
        protected sealed override string? ComputeNamespace()
        {
            Type? declaringType = DeclaringType;
            if (declaringType != null)
                return declaringType.Namespace;
            return TypeDefinition.Namespace.GetStringOrNull(Reader)?.EscapeTypeNameIdentifier();
        }
 
        protected sealed override TypeAttributes ComputeAttributeFlags() => TypeDefinition.Attributes;
 
        internal sealed override RoType? SpecializeBaseType(RoType[] instantiation)
        {
            EntityHandle baseTypeHandle = TypeDefinition.BaseType;
            if (baseTypeHandle.IsNil)
                return null;
            return baseTypeHandle.ResolveTypeDefRefOrSpec(GetEcmaModule(), instantiation.ToTypeContext());
        }
 
        internal sealed override IEnumerable<RoType> SpecializeInterfaces(RoType[] instantiation)
        {
            MetadataReader reader = Reader;
            EcmaModule module = GetEcmaModule();
            TypeContext typeContext = instantiation.ToTypeContext();
            foreach (InterfaceImplementationHandle h in TypeDefinition.GetInterfaceImplementations())
            {
                InterfaceImplementation ifc = h.GetInterfaceImplementation(reader);
                yield return ifc.Interface.ResolveTypeDefRefOrSpec(module, typeContext);
            }
        }
 
        protected sealed override IEnumerable<CustomAttributeData> GetTrueCustomAttributes() => TypeDefinition.GetCustomAttributes().ToTrueCustomAttributes(GetEcmaModule());
 
        internal sealed override bool IsCustomAttributeDefined(ReadOnlySpan<byte> ns, ReadOnlySpan<byte> name) => TypeDefinition.GetCustomAttributes().IsCustomAttributeDefined(ns, name, GetEcmaModule());
        internal sealed override CustomAttributeData? TryFindCustomAttribute(ReadOnlySpan<byte> ns, ReadOnlySpan<byte> name) => TypeDefinition.GetCustomAttributes().TryFindCustomAttribute(ns, name, GetEcmaModule());
 
        public sealed override int MetadataToken => _handle.GetToken();
 
        public sealed override bool IsGenericTypeDefinition => GetGenericParameterCount() != 0;
 
        internal sealed override int GetGenericParameterCount() => GetGenericTypeParametersNoCopy().Length;
        internal sealed override RoType[] GetGenericTypeParametersNoCopy() => _lazyGenericParameters ??= ComputeGenericTypeParameters();
        private RoType[] ComputeGenericTypeParameters()
        {
            EcmaModule module = GetEcmaModule();
            GenericParameterHandleCollection gps = TypeDefinition.GetGenericParameters();
            if (gps.Count == 0)
                return Array.Empty<RoType>();
 
            RoType[] genericParameters = new RoType[gps.Count];
            foreach (GenericParameterHandle h in gps)
            {
                RoType gp = h.ResolveGenericParameter(module);
                genericParameters[gp.GenericParameterPosition] = gp;
            }
            return genericParameters;
        }
        private volatile RoType[]? _lazyGenericParameters;
 
        protected internal sealed override RoType ComputeEnumUnderlyingType()
        {
            //
            // This performs the functional equivalent of the base Type GetEnumUnderlyingType without going through all the BindingFlag lookup overhead.
            //
 
            if (!IsEnum)
                throw new ArgumentException(SR.Arg_MustBeEnum);
 
            MetadataReader reader = Reader;
            TypeContext typeContext = Instantiation.ToTypeContext();
            RoType? underlyingType = null;
            foreach (FieldDefinitionHandle handle in TypeDefinition.GetFields())
            {
                FieldDefinition fd = handle.GetFieldDefinition(reader);
                if ((fd.Attributes & FieldAttributes.Static) != 0)
                    continue;
                if (underlyingType != null)
                    throw new ArgumentException(SR.Argument_InvalidEnum);
                underlyingType = fd.DecodeSignature(GetEcmaModule(), typeContext);
            }
 
            if (underlyingType == null)
                throw new ArgumentException(SR.Argument_InvalidEnum);
            return underlyingType;
        }
 
        protected sealed override void GetPackSizeAndSize(out int packSize, out int size)
        {
            TypeLayout layout = TypeDefinition.GetLayout();
            packSize = layout.PackingSize;
            size = layout.Size;
        }
 
        internal sealed override bool IsTypeNameEqual(ReadOnlySpan<byte> ns, ReadOnlySpan<byte> name)
        {
            MetadataReader reader = Reader;
            TypeDefinition td = TypeDefinition;
            return td.Name.Equals(name, reader) && td.Namespace.Equals(ns, reader);
        }
 
        private new MetadataLoadContext Loader => _module.Loader;
        private MetadataReader Reader => GetEcmaModule().Reader;
 
        private ref readonly TypeDefinition TypeDefinition { get { Loader.DisposeCheck(); return ref _neverAccessThisExceptThroughTypeDefinitionProperty; } }
        [DebuggerBrowsable(DebuggerBrowsableState.Never)]  // Block from debugger watch windows so they don't AV the debugged process.
        private readonly TypeDefinition _neverAccessThisExceptThroughTypeDefinitionProperty;
    }
}