using dnlib.DotNet; using System; using System.Collections.Generic; using System.Linq; using UnityEngine; namespace HybridCLR.Editor.Meta { public class GenericMethod { public MethodDef Method { get; } public List KlassInst { get; } public List MethodInst { get; } private readonly int _hashCode; public GenericMethod(MethodDef method, List classInst, List methodInst) { Method = method; KlassInst = classInst; MethodInst = methodInst; _hashCode = ComputHashCode(); } public GenericMethod ToGenericShare() { return new GenericMethod(Method, MetaUtil.ToShareTypeSigs(KlassInst), MetaUtil.ToShareTypeSigs(MethodInst)); } public override bool Equals(object obj) { GenericMethod o = (GenericMethod)obj; return Method == o.Method && EqualityUtil.EqualsTypeSigArray(KlassInst, o.KlassInst) && EqualityUtil.EqualsTypeSigArray(MethodInst, o.MethodInst); } public override int GetHashCode() { return _hashCode; } public override string ToString() { return $"{Method}|{string.Join(",", (IEnumerable)KlassInst ?? Array.Empty())}|{string.Join(",", (IEnumerable)MethodInst ?? Array.Empty())}"; } private int ComputHashCode() { int hash = MethodEqualityComparer.CompareDeclaringTypes.GetHashCode(Method); if (KlassInst != null) { hash = HashUtil.CombineHash(hash, HashUtil.ComputHash(KlassInst)); } if (MethodInst != null) { hash = HashUtil.CombineHash(hash, HashUtil.ComputHash(MethodInst)); } return hash; } public MethodSpec ToMethodSpec() { IMethodDefOrRef mt = KlassInst != null ? (IMethodDefOrRef)new MemberRefUser(this.Method.Module, Method.Name, Method.MethodSig, new TypeSpecUser(new GenericInstSig(this.Method.DeclaringType.ToTypeSig().ToClassOrValueTypeSig(), this.KlassInst))) : this.Method; return new MethodSpecUser(mt, new GenericInstMethodSig(MethodInst)); } public static GenericMethod ResolveMethod(IMethod method, GenericArgumentContext ctx) { //Debug.Log($"== resolve method:{method}"); TypeDef typeDef = null; List klassInst = null; List methodInst = null; MethodDef methodDef = null; var decalringType = method.DeclaringType; typeDef = decalringType.ResolveTypeDef(); if (typeDef == null) { return null; } GenericInstSig gis = decalringType.TryGetGenericInstSig(); if (gis != null) { klassInst = ctx != null ? gis.GenericArguments.Select(ga => MetaUtil.Inflate(ga, ctx)).ToList() : gis.GenericArguments.ToList(); } methodDef = method.ResolveMethodDef(); if (methodDef == null) { Debug.LogError($"method:{method} ResolveMethodDef() == null"); return null; } if (method is MethodSpec methodSpec) { methodInst = ctx != null ? methodSpec.GenericInstMethodSig.GenericArguments.Select(ga => MetaUtil.Inflate(ga, ctx)).ToList() : methodSpec.GenericInstMethodSig.GenericArguments.ToList(); } return new GenericMethod(methodDef, klassInst, methodInst); } } }