Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Generic Type Names Display in Graphs #2

Closed
alistairjevans opened this issue Aug 6, 2020 · 6 comments · Fixed by #4
Closed

Generic Type Names Display in Graphs #2

alistairjevans opened this issue Aug 6, 2020 · 6 comments · Fixed by #4

Comments

@alistairjevans
Copy link
Member

Do you think it's worth prettifying generic type names in the graph? For example, when I resolve an IEnumerable of a Service I get:

image

It might be nice to be able to give formatted generic names; people use generic services a lot.

image

@tillig
Copy link
Member

tillig commented Aug 6, 2020

Maybe? I know we've run into folks who have tried to load two versions of the same assembly into an AppDomain and wonder why they resolve an IEnumerable<Thing> and the Thing in the enumerable isn't the same type of Thing they think it is. Knowing where the types come from seems interesting to me.

At the same time, I get the point on graph readability; and maybe if you're getting graphs that isn't the place to troubleshoot that sort of issue?

I haven't seen any code snippets or libraries that convert the type names back to something readable. Seems like we'd be doing some level of code generation based on a type name to get it back to a C# look/format.

@alistairjevans
Copy link
Member Author

We could have the prettification optional, defaulted to On, to allow for people who want to see absolutely everything.

At a simple level, the display pseudo-code might just be:

var serviceType = serviceWithType.Type;
var serviceName = serviceType.Name;
if (serviceType.IsGeneric)
{
   serviceName += "<" + string.Join(", ", serviceType.GetGenericArguments().Select(x => x.Name)) + ">";
}

Will that be enough for most cases?

@tillig
Copy link
Member

tillig commented Aug 6, 2020

I think you're going to get into weirdness if it's an IEnumerable<IHandler<T>> or whatever. There's recursion to do that the type name is already doing for you.

I'm also sort of torn on whether we should trim namespaces. I think they should stay, so you get System.Collections.Generic.IEnumerable<Autofac.DotGraph.B1>; though we could maybe trim a couple of common ones like anything starting with System.Collections.Generic or System (like Func<T> or whatever).

The "simplest thing that could possibly work" might be a regex against the type name that's already been resolved.

For example:

(?<type>[\p{Lu}\p{Ll}\p{Lt}\p{Lm}\{Lo}][\.\p{Lu}\p{Ll}\p{Lt}\p{Lm}\{Lo}\p{Nl}\p{Mn}\p{Mc}\p{Nd}\p{Pc}\p{Cf}]*)`\d+(?<openbracket>\[)(?<typeparam>\[[\p{Lu}\p{Ll}\p{Lt}\p{Lm}\{Lo}][\.\p{Lu}\p{Ll}\p{Lt}\p{Lm}\{Lo}\p{Nl}\p{Mn}\p{Mc}\p{Nd}\p{Pc}\p{Cf}]*[^\[\]]+\])(?<closebracket>\])

OK, yeah, that's long and not simple looking, but it breaks down reasonably.

?<type>[\p{Lu}\p{Ll}\p{Lt}\p{Lm}\{Lo}][\.\p{Lu}\p{Ll}\p{Lt}\p{Lm}\{Lo}\p{Nl}\p{Mn}\p{Mc}\p{Nd}\p{Pc}\p{Cf}]*)

A .NET identifier is matched by this set of Unicode character codes. That is, the first character has to be a letter; but after that it can be letters or numbers. I wasn't precise here since I basically allow something like A.1.2.Class as an identifier (the \. in the second group allows that) but... it's good enough.

After that, you have the

`\d+

The count of parameters, so just drop that.

Then the opening bracket that has the types inside.

(?<openbracket>\[)

Here's where I get fuzzy. I'm not sure if each generic type is in brackets, like IDictionary^2[[Key], [Value]] or if it's something more like IDictionary^2[[Key, Value]] (The ^ should be a backtick, but markdown issues.) But I assume it's like the first one, where each generic type parameter is in its own brackets.

(?<typeparam>\[[\p{Lu}\p{Ll}\p{Lt}\p{Lm}\{Lo}][\.\p{Lu}\p{Ll}\p{Lt}\p{Lm}\{Lo}\p{Nl}\p{Mn}\p{Mc}\p{Nd}\p{Pc}\p{Cf}]*[^\[\]]+\])

Match the type name there, but drop all the crap about version and culture.

Finally, closing bracket.

(?<closebracket>\])

Obviously I haven't tested it other than on a quick online regex tester.

Point being, though, the work of recursion is already done for us, so we could do string manipulation to get the pretty name out rather than trying to redo all the work.

Another option would be to do something with Roslyn to generate C# code based on the name and use what gets generated, since that'll be correct guaranteed.

@alistairjevans
Copy link
Member Author

Ahhh, regexes, my old friend. Could do it that way I suppose.

The Roslyn CodeDOM way might be easier to maintain in the future I'd argue. It's also not a super complex API to use. If it helps I've used CodeDOM to generate extension methods before, here: https://github.com/autostep/AutoStep/blob/develop/tools/ExtensionMethodsGenerator/Program.cs

@tillig
Copy link
Member

tillig commented Aug 7, 2020

The Roslyn way would also probably be more reliable.

@alistairjevans
Copy link
Member Author

Just adding this to the v6 release so we can track it.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging a pull request may close this issue.

2 participants