//The ID of a generic method uses postfix ``n, n is the count of in method parameters, for example, System.Tuple.Create``1(``0) public override void Build(ECMAStore store) { if (DocId != null && DocId.Contains('|')) { var parts = DocId.Split(':'); if (parts?.Length == 2) { Id = parts[1]; if (Id.StartsWith(Parent.Uid)) { Id = Id.Substring(Parent.Uid.Length, Id.Length - Parent.Uid.Length).TrimStart('.'); return; } } } Id = Name.Replace('.', '#'); if (TypeParameters?.Count > 0) { Id = Id.Substring(0, Id.LastIndexOf('<')) + "``" + TypeParameters.Count; } //handle eii prefix Id = Id.Replace('<', '{').Replace('>', '}'); Id = Id.Replace(',', '@'); if (Parameters?.Count > 0) { //Type conversion operator can be considered a special operator whose name is the UID of the target type, //with one parameter of the source type. //For example, an operator that converts from string to int should be Explicit(System.String to System.Int32). if (Name == "op_Explicit" || Name == "op_Implicit") { var typeParamsOnType = Parent.TypeParameters?.Select(tp => tp.Name).ToList(); var typeParamsOnMember = TypeParameters?.Select(tp => tp.Name).ToList(); var rtype = ReturnValueType.VersionedTypes.First().Value; Id += string.Format("({0})~{1}", Parameters.First().Type.ToSpecId(typeParamsOnType, typeParamsOnMember), rtype.ToSpecId(typeParamsOnType, typeParamsOnMember)); } //spec is wrong, no need to treat indexer specially, so comment this part out //else if (MemberType == MemberType.Property && Signatures.ContainsKey("C#") && Signatures["C#"].Contains("[")) //{ // Id += string.Format("[{0}]", string.Join(",", GetParameterUids(store))); //} else { Id += string.Format("({0})", string.Join(",", GetParameterUids(store))); } } //special handling for compatibility in UWP legacy MD content if (store.UWPMode && DocId != null) { var pos1 = Id.IndexOf('('); var pos2 = DocId.IndexOf('('); if (pos1 > 0 && pos2 > 0) { Id = Id.Substring(0, pos1) + DocId.Substring(pos2); } } }