Question

We're using the Visual Studio CodeModel and have some problems to get the generic parameters of a CodeType. How to obtain them without parsing the FullName ourselves?

It is hinted (although not marked an answer) in How can I get the generic constraints from CodeInterface as a CodeType object? that there is no other way, however, this is not really believable as:

System.Func<Outer.Inner>

would not be defined: You cannot know if the generic parameter you've parsed (Outer.Inner) is referring to the namespace Outer containing a class Inner or if it is referring to the class Outer having an inner class Inner (and yes, it is not Outer+Inner in such cases).

If somebody at least knows how to tell the FullName property to show nested classes with a + sign this would be great too.

Was it helpful?

Solution

I think the answer here is pretty definitive. This isn't supported by DTE or DTE2 and is unlikely to be supported in the future.

The only way currently is to use Roslyn, which is not acceptable for those of us that don't want to use pre-release software. I also haven't looked into what kinds of dependencies that will entail (do users of my component need to install Roslyn?).

You could use a regular expression to get the types from the FullName string. But, for those of us in the real world who need the token (T) to concrete type (System.String) mapping, this is not an option.

OTHER TIPS

I can't find a way to do it for any generic type, but if you need to do it for a specific type, it is possible in some cases.

For instance, I have the following code to check if a type is a collection, and if it is, get the element type:

    private static bool IsCollectionType(CodeType type, out CodeType elementType)
    {
        // string implements IEnumerable<char>, but we don't want to treat it as a collection
        if (type.FullName == "System.String")
        {
            elementType = null;
            return false;
        }

        var enumerable = type.Bases.OfType<CodeInterface>().FirstOrDefault(i => i.FullName.StartsWith("System.Collections.Generic.IEnumerable<"));
        var method = enumerable?.Members.OfType<CodeFunction>().FirstOrDefault(m => m.Name == "GetEnumerator");
        var enumerator = method?.Type.CodeType;
        var current = enumerator?.Members.OfType<CodeProperty>().FirstOrDefault(m => m.Name == "Current");
        if (current != null)
        {
            elementType = current.Type.CodeType;
            return true;
        }

        elementType = null;
        return false;
    }

As you can see, I'm not directly looking at the generic type argument, but instead I look at the type of IEnumerable<T>.GetEnumerator().Current. Of course, this requires specific knowledge about the type you're working with.

Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top