Get fully-qualified metadata name in Roslyn

c#, roslyn

Solution

For now, having no better solution, I'm using the following:

public static string GetFullMetadataName(this ISymbol s) 
{
    if (s == null || IsRootNamespace(s))
    {
        return string.Empty;
    }

    var sb = new StringBuilder(s.MetadataName);
    var last = s;

    s = s.ContainingSymbol;

    while (!IsRootNamespace(s))
    {
        if (s is ITypeSymbol && last is ITypeSymbol)
        {
            sb.Insert(0, '+');
        }
        else
        {
            sb.Insert(0, '.');
        }

        sb.Insert(0, s.OriginalDefinition.ToDisplayString(SymbolDisplayFormat.MinimallyQualifiedFormat));
        //sb.Insert(0, s.MetadataName);
        s = s.ContainingSymbol;
    }

    return sb.ToString();
}

private static bool IsRootNamespace(ISymbol symbol) 
{
    INamespaceSymbol s = null;
    return ((s = symbol as INamespaceSymbol) != null) && s.IsGlobalNamespace;
}

which seems to work for now. Roslyn seems to have internal flags for `SymbolDisplayFormat` that enable that sort of thing (most notably SymbolDisplayCompilerInternalOptions.UseArityForGenericTypes, but not accessible to the outside.

Above code could probably be faster on recent .NET versions by using `Append` instead of `Insert` on the `StringBuilder`, but that's something to leave for profiling.

Problem

I need to get the full CLR name of a particular symbol. This means that for generic types I need the ``1`, ``2`, etc. appended to types. Now, `ISymbol` already has a property `MetadataName` which does exactly that. But it excludes surrounding types and namespaces, only giving the name of the symbol at hand. The usual option for getting a fully-qualified name, i.e. via `ToDisplayString` doesn't quite work here because it will not use the `MetadataName` for its various parts. Is there anything like this built-in? Or do I have to just concatenate the chain of `ContainingSymbol`s with `.` in between? (And are there points where this assumption breaks down?) EDIT: Just noticed that you need a `+` in between individual names if it's a type contained in another type, but apart from that, using `.` should work, I guess.

Original source

Related problems