// dnlib: See LICENSE.txt for more info using System; using System.Collections.Generic; using System.Diagnostics; using System.Threading; using dnlib.DotNet.MD; using dnlib.DotNet.Pdb; namespace dnlib.DotNet { /// /// A high-level representation of a row in the GenericParamConstraint table /// public abstract class GenericParamConstraint : IHasCustomAttribute, IHasCustomDebugInformation, IContainsGenericParameter { /// /// The row id in its table /// protected uint rid; /// public MDToken MDToken => new MDToken(Table.GenericParamConstraint, rid); /// public uint Rid { get => rid; set => rid = value; } /// public int HasCustomAttributeTag => 20; /// /// Gets the owner generic param /// public GenericParam Owner { get => owner; internal set => owner = value; } /// protected GenericParam owner; /// /// From column GenericParamConstraint.Constraint /// public ITypeDefOrRef Constraint { get => constraint; set => constraint = value; } /// protected ITypeDefOrRef constraint; /// /// Gets all custom attributes /// public CustomAttributeCollection CustomAttributes { get { if (customAttributes is null) InitializeCustomAttributes(); return customAttributes; } } /// protected CustomAttributeCollection customAttributes; /// Initializes protected virtual void InitializeCustomAttributes() => Interlocked.CompareExchange(ref customAttributes, new CustomAttributeCollection(), null); /// public bool HasCustomAttributes => CustomAttributes.Count > 0; /// public int HasCustomDebugInformationTag => 20; /// public bool HasCustomDebugInfos => CustomDebugInfos.Count > 0; /// /// Gets all custom debug infos /// public IList CustomDebugInfos { get { if (customDebugInfos is null) InitializeCustomDebugInfos(); return customDebugInfos; } } /// protected IList customDebugInfos; /// Initializes protected virtual void InitializeCustomDebugInfos() => Interlocked.CompareExchange(ref customDebugInfos, new List(), null); bool IContainsGenericParameter.ContainsGenericParameter => TypeHelper.ContainsGenericParameter(this); } /// /// A GenericParamConstraintAssembly row created by the user and not present in the original .NET file /// public class GenericParamConstraintUser : GenericParamConstraint { /// /// Default constructor /// public GenericParamConstraintUser() { } /// /// Constructor /// /// The constraint public GenericParamConstraintUser(ITypeDefOrRef constraint) => this.constraint = constraint; } /// /// Created from a row in the GenericParamConstraint table /// sealed class GenericParamConstraintMD : GenericParamConstraint, IMDTokenProviderMD, IContainsGenericParameter2 { /// The module where this instance is located readonly ModuleDefMD readerModule; readonly uint origRid; readonly GenericParamContext gpContext; /// public uint OrigRid => origRid; bool IContainsGenericParameter2.ContainsGenericParameter => TypeHelper.ContainsGenericParameter(this); /// protected override void InitializeCustomAttributes() { var list = readerModule.Metadata.GetCustomAttributeRidList(Table.GenericParamConstraint, origRid); var tmp = new CustomAttributeCollection(list.Count, list, (list2, index) => readerModule.ReadCustomAttribute(list[index])); Interlocked.CompareExchange(ref customAttributes, tmp, null); } /// protected override void InitializeCustomDebugInfos() { var list = new List(); readerModule.InitializeCustomDebugInfos(new MDToken(MDToken.Table, origRid), gpContext, list); Interlocked.CompareExchange(ref customDebugInfos, list, null); } /// /// Constructor /// /// The module which contains this GenericParamConstraint row /// Row ID /// Generic parameter context /// If is null /// If is invalid public GenericParamConstraintMD(ModuleDefMD readerModule, uint rid, GenericParamContext gpContext) { #if DEBUG if (readerModule is null) throw new ArgumentNullException("readerModule"); if (readerModule.TablesStream.GenericParamConstraintTable.IsInvalidRID(rid)) throw new BadImageFormatException($"GenericParamConstraint rid {rid} does not exist"); #endif origRid = rid; this.rid = rid; this.readerModule = readerModule; this.gpContext = gpContext; bool b = readerModule.TablesStream.TryReadGenericParamConstraintRow(origRid, out var row); Debug.Assert(b); constraint = readerModule.ResolveTypeDefOrRef(row.Constraint, gpContext); owner = readerModule.GetOwner(this); } internal GenericParamConstraintMD InitializeAll() { MemberMDInitializer.Initialize(Owner); MemberMDInitializer.Initialize(Constraint); MemberMDInitializer.Initialize(CustomAttributes); return this; } } }