File: System\Reflection\Metadata\TypeSystem\MemberReference.cs
Web Access
Project: src\runtime\src\libraries\System.Reflection.Metadata\src\System.Reflection.Metadata.csproj (System.Reflection.Metadata)
// Licensed to the .NET Foundation under one or more agreements.
// The .NET Foundation licenses this file to you under the MIT license.

using System.Reflection.Metadata.Ecma335;

namespace System.Reflection.Metadata
{
    public readonly struct MemberReference
    {
        private readonly MetadataReader _reader;

        // Workaround: JIT doesn't generate good code for nested structures, so use RowId.
        private readonly uint _treatmentAndRowId;

        internal MemberReference(MetadataReader reader, uint treatmentAndRowId)
        {
            _reader = reader;
            _treatmentAndRowId = treatmentAndRowId;
        }

        private int RowId
        {
            get { return (int)(_treatmentAndRowId & TokenTypeIds.RIDMask); }
        }

        private MemberRefTreatment Treatment
        {
            get { return (MemberRefTreatment)(_treatmentAndRowId >> TokenTypeIds.RowIdBitCount); }
        }

        private MemberReferenceHandle Handle
        {
            get { return MemberReferenceHandle.FromRowId(RowId); }
        }

        /// <summary>
        /// MethodDef, ModuleRef,TypeDef, TypeRef, or TypeSpec handle.
        /// </summary>
        public EntityHandle Parent
        {
            get
            {
                if (Treatment == 0)
                {
                    return _reader.MemberRefTable.GetClass(Handle);
                }

                return GetProjectedParent();
            }
        }

        public StringHandle Name
        {
            get
            {
                if (Treatment == 0)
                {
                    return _reader.MemberRefTable.GetName(Handle);
                }

                return GetProjectedName();
            }
        }

        /// <summary>
        /// Gets a handle to the signature blob.
        /// </summary>
        public BlobHandle Signature
        {
            get
            {
                if (Treatment == 0)
                {
                    return _reader.MemberRefTable.GetSignature(Handle);
                }

                return GetProjectedSignature();
            }
        }

        public TType DecodeFieldSignature<TType, TGenericContext>(ISignatureTypeProvider<TType, TGenericContext> provider, TGenericContext genericContext)
        {
            var decoder = new SignatureDecoder<TType, TGenericContext>(provider, _reader, genericContext);
            var blobReader = _reader.GetBlobReader(Signature);
            return decoder.DecodeFieldSignature(ref blobReader);
        }

        public MethodSignature<TType> DecodeMethodSignature<TType, TGenericContext>(ISignatureTypeProvider<TType, TGenericContext> provider, TGenericContext genericContext)
        {
            var decoder = new SignatureDecoder<TType, TGenericContext>(provider, _reader, genericContext);
            var blobReader = _reader.GetBlobReader(Signature);
            return decoder.DecodeMethodSignature(ref blobReader);
        }

        /// <summary>
        /// Determines if the member reference is to a method or field.
        /// </summary>
        /// <exception cref="BadImageFormatException">The member reference signature is invalid.</exception>
        public MemberReferenceKind GetKind()
        {
            BlobReader blobReader = _reader.GetBlobReader(this.Signature);
            SignatureHeader header = blobReader.ReadSignatureHeader();

            return header.Kind switch
            {
                SignatureKind.Method => MemberReferenceKind.Method,
                SignatureKind.Field => MemberReferenceKind.Field,
                _ => throw new BadImageFormatException(),
            };
        }

        public CustomAttributeHandleCollection GetCustomAttributes()
        {
            return new CustomAttributeHandleCollection(_reader, Handle);
        }

#region Projections

        private EntityHandle GetProjectedParent()
        {
            // no change
            return _reader.MemberRefTable.GetClass(Handle);
        }

        private StringHandle GetProjectedName()
        {
            if (Treatment == MemberRefTreatment.Dispose)
            {
                return StringHandle.FromVirtualIndex(StringHandle.VirtualIndex.Dispose);
            }

            return _reader.MemberRefTable.GetName(Handle);
        }

        private BlobHandle GetProjectedSignature()
        {
            // no change
            return _reader.MemberRefTable.GetSignature(Handle);
        }
#endregion
    }
}