egametang/ET · error · Exception

[PreservedMethod] method:{method} has generic parameters

Error message

[PreservedMethod] method:{method} has generic parameters

What it means

Thrown by Generator.ProcessMethod when a method has HasGenericParameters == true and there is no class or method instantiation (klassInst == null and methodInst == null). ProcessMethod handles both instantiated and non-instantiated methods; for the non-instantiated path it requires the method to be non-generic, because an open generic method has no concrete signature to bridge.

Source

Thrown at Packages/cn.etetet.hybridclr/Scripts/Editor/Share/MethodBridge/Generator.cs:205

            if (method.IsPrivate || (method.IsAssembly && !method.IsPublic && !method.IsFamily))
            {
                if (klassInst == null && methodInst == null)
                {
                    return;
                }
                else
                {
                    //Debug.Log($"[PreservedMethod] method:{method}");
                }
            }
            ICorLibTypes corLibTypes = method.Module.CorLibTypes;
            TypeSig returnType;
            List<TypeSig> parameters;
            if (klassInst == null && methodInst == null)
            {
                if (method.HasGenericParameters)
                {
                    throw new Exception($"[PreservedMethod] method:{method} has generic parameters");
                }
                returnType = MetaUtil.ToShareTypeSig(corLibTypes, method.ReturnType);
                parameters = method.Parameters.Select(p => MetaUtil.ToShareTypeSig(corLibTypes, p.Type)).ToList();
            }
            else
            {
                var gc = new GenericArgumentContext(klassInst, methodInst);
                returnType = MetaUtil.ToShareTypeSig(corLibTypes, MetaUtil.Inflate(method.ReturnType, gc));
                parameters = method.Parameters.Select(p => MetaUtil.ToShareTypeSig(corLibTypes, MetaUtil.Inflate(p.Type, gc))).ToList();
            }

            var m2nMethod = CreateMethodDesc(method, false, returnType, parameters);
            AddManaged2NativeMethod(m2nMethod);

            if (method.IsVirtual)
            {
                if (method.DeclaringType.IsInterface)
                {

View on GitHub (pinned to 5cab01f7a8)

Solutions

  1. Run HybridCLR/Generate/AOTGenericReference so all generic instantiations are collected and ProcessMethod receives concrete klassInst/methodInst.
  2. If the method should never be bridged generically, remove it from preserved/reverse-P/Invoke targets.
  3. Refactor the method to be non-generic or ensure every call site uses explicit concrete type arguments that the collector can see.
  4. Re-run HybridCLR/Generate/All after collecting instantiations.
Defensive patterns

Strategy: validation

Validate before calling

// In ProcessMethod: guard the non-instantiated path
if (klassInst == null && methodInst == null && method.HasGenericParameters)
    Debug.LogError("Method is generic with no instantiation -- cannot bridge.");

Prevention

When it happens

Trigger: ProcessMethod(method, klassInst=null, methodInst=null) is reached for a method that is referenced as a preserved/bridge target without a concrete instantiation, and method.HasGenericParameters is true. The code throws before computing returnType/parameters.

Common situations: A generic method is referenced (e.g. via MonoPInvokeCallback or a preserved list) without specifying type arguments; the generic reference collector did not record the instantiation; a new generic method was added to a type that participates in reverse P/Invoke.

Related errors


AI-assisted analysis of egametang/ET@5cab01f7a8 (2026-08-13). Data as JSON: /api/errors/7076c04669a0b2c0. Report an issue: GitHub.