Question Details

No question body available.

Tags

c# .net mono.cecil

Answers (2)

February 11, 2026 Score: 1 Rep: 177 Quality: Low Completeness: 60%

The core result is: you need Inflation, no pun intended :D

List implements ICollection in its definition, so Cecil stores that interface as ICollection (generic parameter).
When your class inherits List, Cecil does not automatically replace !0 with string for you.

So you need to look at the base type instance (List) and manually substitute the generic parameters.

The important part is: don’t read List’s interfaces and expect Cecil to magically turn them into List’s interfaces. It won’t. You have to inflate them.

Here’s a way to do it:

using Mono.Cecil;
using System.Collections.Generic;
using System.Linq;

static TypeReference? GetCollectionItemType(TypeReference type) { var map = new Dictionary();

foreach (var current in GetTypeHierarchy(type)) { // If current is something like List, record that T -> string if (current is GenericInstanceType git) { var def = git.ElementType.Resolve();

for (int i = 0; i < def.GenericParameters.Count; i++) map[def.GenericParameters[i]] = ResolveGeneric(git.GenericArguments[i], map); }

var defn = current.Resolve();

foreach (var iface in defn.Interfaces.Select(x => ResolveGeneric(x.InterfaceType, map))) { if (iface is GenericInstanceType gif && (gif.ElementType.FullName == "System.Collections.Generic.ICollection`1" || gif.ElementType.FullName == "System.Collections.Generic.IReadOnlyCollection`1")) { return ResolveGeneric(gif.GenericArguments[0], map); } } }

return null; }

static IEnumerable GetTypeHierarchy(TypeReference type) { for (var cur = type; cur != null; ) { yield return cur; cur = cur.Resolve()?.BaseType; } }

static TypeReference ResolveGeneric(TypeReference type, Dictionary map) { if (type is GenericParameter gp && map.TryGetValue(gp, out var replacement)) return replacement;

if (type is GenericInstanceType git) { var resolved = new GenericInstanceType(ResolveGeneric(git.ElementType, map)); foreach (var arg in git.GenericArguments) resolved.GenericArguments.Add(ResolveGeneric(arg, map)); return resolved; }

return type; }
February 11, 2026 Score: 0 Rep: 1,492 Quality: Low Completeness: 60%

I'm not sure if you need Mono.Cecil for this specific task because it can be simply implemented with the regular .Net Reflection.

Here is my own implementation of the GetTypeHierarchy helper:

public IEnumerable GetTypeHierarchy(Type t)
{
     Type current = t;

while (current != null) { yield return current; current = current.BaseType; } }

You can make a check like this then

public Type? GetItemType(Type type)
{
    var collectionInterfaceType = GetTypeHierarchy(type)
    .SelectMany(t => t.GetInterfaces())
    .FirstOrDefault(interfaceType => interfaceType.FullName.StartsWith("System.Collections.Generic.ICollection`1") || 
                                     interfaceType.FullName.StartsWith("System.Collections.Generic.IReadOnlyCollection`1"));

if (collectionInterfaceType != null) { var itemType = collectionInterfaceType.GenericTypeArguments[0]; return itemType; }

return null; }

Note that I used StartsWith string method instead of == check because for generic methods the == check won't work. For example, for typeof(List).FullName the C# Interactive REPL in VS displays the following:

> typeof(List).FullName
"System.Collections.Generic.List`1[[System.String, System.Private.CoreLib, Version=8.0.0.0, Culture=neutral, PublicKeyToken=7cec85d7bea7798e]]"

If you have to used Mono.Cecil, then perhaps changing the check of type names in your code will fix the issue.