ExpressionTreeToString icon indicating copy to clipboard operation
ExpressionTreeToString copied to clipboard

Configuration of displayed type names

Open jahav opened this issue 5 years ago • 2 comments

Version info:

  • Visual Studio version: 2019 Community edition
  • Version: 2.0.15.0

Is your feature request related to a problem? Please describe.
I need to see a different string that simple name of a type in the visualizer. I am creating a proxy classes (using reflection) and transforming an original expression into one that uses proxy classes. I want to write tests that verify the expression was correctly rewritten into proxy classes.

Screenshots
I have an expression

Expression<Func<CustomerEntity, Address>> identity = _ => new Address();

where CustomerEntity is from namespace ValueConvertor.Test and I am converting the expression so it uses a generated proxy class Middleware.ValueConvertor.Test

and in all visualizers it is displayed without a namespace (example for "Textual tree")

Lambda (Func<CustomerEntity, Address>)
        · Parameters[0] - Parameter (CustomerEntity) _
        · Body - New (Address)

Describe the solution you'd like
A delegate to transform a Type into a text that can be customized as I desire. Either as a static class used by all formatters or a parameter passed to a ToString method or a combination of both (static class as a default that would be overriden when a parameter would be passed to ToString method).

Something like

public interface IVisualizerConfigurationProvider
{
	Func<Type, string> GetTypeName { get; }
}

public sealed class VisualizerConfiguration
{
	private VisualizerConfiguration() {}

	public static IVisualizerConfigurationProvider Default { get; set; } = new DefaultConfiguration();

	private class DefaultConfiguration : IVisualizerConfigurationProvider
	{
		public Func<Type, string> GetTypeDisplayLabel => x => x.Name;
	}
}

and I could change it to custom type

VisualizerConfiguration.Default = new ProxyVisualizer();

internal sealed class ProxyVisualizer : IVisualizerConfigurationProvider
{
	public Func<Type, string> GetTypeDisplayLabel { get; } = ConvertProxyLeaveRest;

        private static string ConvertProxyLeaveRest(Type type)
	{
		if (type.Assembly.GetName().Name == "dynamicProxyAssembly" 
                && type.Namespace.StartsWith("Middleware.")) 
			return "«" + type.Name + "»";
		return type.Name;
     }
}

I could write type names including namespaces or anything I want and not worry about two types having same name.

Describe alternatives you've considered
I can use a suffix in my proxy type generator, but that is not good. Since types are dynamically generated, I have a limited number of options how to easily write assertions in my tests that are readable.

My current solution is to generate different type names for tests and different one for release.

It is not a significant trouble, but I would prefer to not have my tests influence the type names of my proxies.

jahav avatar Jan 17 '20 22:01 jahav

I will try to add this at some point, but I can't provide a precise timeline.

Why is the following interface necessary?

public interface IVisualizerConfigurationProvider
{
	Func<Type, string> GetTypeName { get; }
}

Isn't the delegate type (Func<Type, string>) enough on its own?

zspitz avatar Jan 19 '20 14:01 zspitz

On further consideration, it may not be necessary to pass an option to the RenderLiteral function. All that is needed is to expose two additional extension points: WriteTypename and WriteLiteral, which would allow extending a given writer/visitor with custom rendering for type names and literals. A new delegate could be used to replace the original delegate.

@jahav Is this still an issue for you? Would this be a valid solution?

zspitz avatar Oct 31 '20 22:10 zspitz