agileobjects / readableexpressions Goto Github PK
View Code? Open in Web Editor NEWA library and Debugger Visualizer which translates Expression Trees into readable C# source code. .NET 3.5+ and .NET Standard 1.0+.
License: MIT License
A library and Debugger Visualizer which translates Expression Trees into readable C# source code. .NET 3.5+ and .NET Standard 1.0+.
License: MIT License
VS 2019 Preview 1 added custom visualizer support for .NET Core apps, but trying to use ReadableExpressions in one results in the following error:
Unable to load the custom visualizer.
Additional informaiton:
The debuggee-side visualizer assembly 'AgileObjects.ReadableExpressions.Visualizers.Vs16, Version=2.0.0.0, Culture=neutral, PublicKeyToken=null' was not found at path 'C:\Program Files (x86)\Microsoft Visual Studio\2019\Preview\Common7\Packages\Debugger\Visualizers\netstandard2.0'.
Copying the assembly to the path mentioned in the error fixes the problem.
I'm encountering the same behavior as reported here. However, I'm not using .NET Core; I'm using .NET Framework v4.7.1.
I previously reported this in the MarketPlace Q&A, but I think I've figured out what might be happening.
Based on the attached log, it seems that installation succeeded. It appears I've been laboring under the mistaken impression that it didn't, because the installer didn't pause to indicate success. Most MSIs doβin fact, this is the first one I've encountered in all these years that doesn't.
I do now have the assembly "C:\Program Files (x86)\Microsoft Visual Studio\2017\Professional\Common7\Packages\Debugger\Visualizers\AgileObjects.ReadableExpressions.Visualizers.Vs15.dll"
as indicated. I haven't tried to use it yet, as I don't have any code handy for which I need it (I'm trying this out for potential future use).
Anyway... with this now it seems all is well.
Can you confirm that my experience aligns with the expected behavior of the MSI?
The visualizer window only scrolls vertically, so if a translated expression is 'wide' the vertical scrollbar is pushed beyond the right-hand boundary of the window and is inaccessible.
The 2.1.2 installer which is what is downloaded from the VS Marketplace appears to detect VS 2013 (12.0) on a system where it is not fully installed. My guess is some bits of the 12.0 system, but not the entire visual studio, is laid down as part of another product. I only have two subdirectories of C:\Program Files (x86)\Microsoft Visual Studio 12.0\Common7, and those are IDE and Tools. The MSI installation log is as follows:
Calling custom action ReadableExpressions.Visualizers.Installer.Custom!AgileObjects.ReadableExpressions.Visualizers.Installer.Custom.VisualizerInstallationActions.Install
Starting...
System.IO.DirectoryNotFoundException: Could not find a part of the path 'C:\Program Files (x86)\Microsoft Visual Studio 12.0\Common7\Packages\Debugger\Visualizers'.
The 2.1.1 installer does install successfully, and it reports the visualizers were installed for 10.0, 12.0, and 16.0. I actually do have VS 10.0 and 16.0 installed.
It's not often I need to use your visualizer, but, it is powerful - thanks for the project and let me know if I can be more helpful in troubleshooting this issue.
no issue here, just wanted to give a big thanks to this project. its working great.
So, i have to mention that.
When opening preview window, it takes a seconds to open. Then after closing it - VS hangs for the same time. As result i prefer to quickly review string line instead of invoking more readable view.
Any ideas why?
Hi there! Extremely useful extension!
I've been using it for quite a while now, but after I reinstalled Visual Studio 2019 (I'm on version 16.8.1 right now), whenever I click on the magnifier button, I get the following error window:
I was going to try uninstalling and then installing the extension again, but the "Uninstall" button is grayed out:
I'd appreciate any help.
System.Runtime.InteropServices.COMException (0x80004005): Error HRESULT E_FAIL has been returned from a call to a COM component.
at System.Windows.Forms.UnsafeNativeMethods.IWebBrowser2.get_RegisterAsDropTarget()
at System.Windows.Forms.WebBrowser.set_AllowWebBrowserDrop(Boolean value)
at AgileObjects.ReadableExpressions.Visualizers.Core.VisualizerDialog.OnShown(EventArgs e)
at System.Windows.Forms.Form.CallShownEvent()
at System.Windows.Forms.Control.InvokeMarshaledCallbackDo(ThreadMethodEntry tme)
at System.Windows.Forms.Control.InvokeMarshaledCallbackHelper(Object obj)
at System.Threading.ExecutionContext.RunInternal(ExecutionContext executionContext, ContextCallback callback, Object state, Boolean preserveSyncCtx)
at System.Threading.ExecutionContext.Run(ExecutionContext executionContext, ContextCallback callback, Object state, Boolean preserveSyncCtx)
at System.Threading.ExecutionContext.Run(ExecutionContext executionContext, ContextCallback callback, Object state)
at System.Windows.Forms.Control.InvokeMarshaledCallback(ThreadMethodEntry tme)
at System.Windows.Forms.Control.InvokeMarshaledCallbacks()
Fixed by restarting VS :)
Version 3.1.0
Visualize any expression, and move window up by mouse, release, move again.
You can examine preview window expanding.
Expression:
.Lambda #Lambda1<System.Action`2[System.Object,System.Object]>(
System.Object $obj,
System.Object $value) {
.Block(System.Int32 $var1) {
$var1 = 0
}
}
Expected:
// generate unique name for variable, e.g. $varN
(obj, value) => var $var1 = 0
Actual:
(obj, value) => var = 0
The Increment
and Decrement
expression types are diassembled like pre-increment/pre-decrement operators, but these operators are really only the equivalent of operand + 1
and operand - 1
.
This expression:
var x =
Expression.Variable(typeof(byte), "x");
Expression.Assign(
x,
Expression.Convert(
Expression.Increment(
Expression.Convert(x, typeof(int))
),
typeof(byte)
)
)
.ToReadableString()
.Dump();
outputs x = (byte)++(int)x
, when x = (byte)((int) + 1)
is the correct interpretation.
In idiomatic C#, this is x += 1
for a variable of type byte
.
Sorry for too much code, as it is a part of big testcase.
required types
interface IQueryRunner
{
IDataContext DataContext { get; }
Expression Expression { get; }
object[] Parameters { get; }
}
interface IDataContext
{
}
interface IDataReader
{
}
class DataContext : IDataContext
{
}
class QueryRunner : IQueryRunner
{
IDataContext IQueryRunner.DataContext => new DataContext();
Expression IQueryRunner.Expression => Expression.Constant(null);
object[] IQueryRunner.Parameters => Array.Empty<object>();
}
class SQLiteDataReader : IDataReader
{
public bool IsDBNull(int idx)
{
return default;
}
public int GetInt32(int idx)
{
return default;
}
public Guid GetGuid(int idx)
{
return default;
}
}
class InheritanceTests
{
public enum TypeCodeEnum
{
Base,
A,
A1,
A2,
}
public abstract class InheritanceBase
{
public Guid GuidValue { get; set; }
public virtual TypeCodeEnum TypeCode
{
get { return TypeCodeEnum.Base; }
}
}
public abstract class InheritanceA : InheritanceBase
{
public List<InheritanceB> Bs { get; set; }
public override TypeCodeEnum TypeCode
{
get { return TypeCodeEnum.A; }
}
}
public class InheritanceB : InheritanceBase
{
}
public class InheritanceA2 : InheritanceA
{
public override TypeCodeEnum TypeCode
{
get { return TypeCodeEnum.A2; }
}
}
public class InheritanceA1 : InheritanceA
{
public override TypeCodeEnum TypeCode
{
get { return TypeCodeEnum.A1; }
}
}
}
class TableBuilder
{
public class TableContext
{
public static object OnEntityCreated(IDataContext context, object entity)
{
return entity;
}
}
}
public enum Test
{
One,
Two
}
Expression:
var a1 = Expression.Parameter(typeof(IQueryRunner), "qr");
var a2 = Expression.Parameter(typeof(IDataContext), "dctx");
var a3 = Expression.Parameter(typeof(IDataReader), "rd");
var a4 = Expression.Parameter(typeof(Expression), "expr");
var a5 = Expression.Parameter(typeof(object[]), "ps");
var ldr = Expression.Variable(typeof(SQLiteDataReader), "ldr");
var mapperBody = Expression.Block(
new[] { ldr },
Expression.Assign(ldr, Expression.Convert(a3, typeof(SQLiteDataReader)) ),
Expression.Condition(
Expression.Equal(
Expression.Condition(
Expression.Call(ldr, nameof(SQLiteDataReader.IsDBNull), null, Expression.Constant(0)),
Expression.Constant(InheritanceTests.TypeCodeEnum.Base),
Expression.Convert(
Expression.Call(ldr, nameof(SQLiteDataReader.GetInt32), null, Expression.Constant(0)),
typeof(InheritanceTests.TypeCodeEnum))),
Expression.Constant(InheritanceTests.TypeCodeEnum.A1)),
Expression.Convert(
Expression.Convert(
Expression.Call(
typeof(TableBuilder.TableContext).GetMethod(nameof(TableBuilder.TableContext.OnEntityCreated)),
a2,
Expression.MemberInit(
Expression.New(typeof(InheritanceTests.InheritanceA1)),
Expression.Bind(
typeof(InheritanceTests.InheritanceA1).GetProperty("GuidValue"),
Expression.Condition(
Expression.Call(ldr, nameof(SQLiteDataReader.IsDBNull), null, Expression.Constant(1)),
Expression.Constant(Guid.Empty),
Expression.Call(ldr, nameof(SQLiteDataReader.GetGuid), null, Expression.Constant(1))))
)
),
typeof(InheritanceTests.InheritanceA1)),
typeof(InheritanceTests.InheritanceA)),
Expression.Convert(
Expression.Convert(
Expression.Call(
typeof(TableBuilder.TableContext).GetMethod(nameof(TableBuilder.TableContext.OnEntityCreated)),
a2,
Expression.MemberInit(
Expression.New(typeof(InheritanceTests.InheritanceA2)),
Expression.Bind(
typeof(InheritanceTests.InheritanceA2).GetProperty("GuidValue"),
Expression.Condition(
Expression.Call(ldr, nameof(SQLiteDataReader.IsDBNull), null, Expression.Constant(1)),
Expression.Constant(Guid.Empty),
Expression.Call(ldr, nameof(SQLiteDataReader.GetGuid), null, Expression.Constant(1))))
)
),
typeof(InheritanceTests.InheritanceA2)),
typeof(InheritanceTests.InheritanceA))));
var mapper = Expression.Lambda<Func<IQueryRunner, IDataContext, IDataReader, Expression, object[], InheritanceTests.InheritanceA>>(mapperBody, a1, a2, a3, a4, a5);
var p1 = Expression.Parameter(typeof(IQueryRunner), "qr");
var p2 = Expression.Parameter(typeof(IDataReader), "dr");
var body = Expression.Invoke(
mapper,
p1,
Expression.Property(p1, nameof(IQueryRunner.DataContext)),
p2,
Expression.Property(p1, nameof(IQueryRunner.Expression)),
Expression.Property(p1, nameof(IQueryRunner.Parameters)));
var lambda = Expression.Lambda<Func<IQueryRunner, IDataReader, InheritanceTests.InheritanceA>>(body, p1, p2);
Expected:
(qr, dr) => ((
qr,
dctx,
rd,
expr,
ps) =>
{
var ldr = (Issue83_linq2db.SQLiteDataReader)rd;
return (ldr.IsDBNull(0)
? Issue83_linq2db.InheritanceTests.TypeCodeEnum.Base
: (Issue83_linq2db.InheritanceTests.TypeCodeEnum)ldr.GetInt32(0)) == Issue83_linq2db.InheritanceTests.TypeCodeEnum.A1
? (Issue83_linq2db.InheritanceTests.InheritanceA)((Issue83_linq2db.InheritanceTests.InheritanceA1)Issue83_linq2db.TableBuilder.TableContext.OnEntityCreated(
dctx,
new Issue83_linq2db.InheritanceTests.InheritanceA1
{
GuidValue = ldr.IsDBNull(1) ? default(Guid) : ldr.GetGuid(1)
}))
: (Issue83_linq2db.InheritanceTests.InheritanceA)((Issue83_linq2db.InheritanceTests.InheritanceA2)Issue83_linq2db.TableBuilder.TableContext.OnEntityCreated(
dctx,
new Issue83_linq2db.InheritanceTests.InheritanceA2
{
GuidValue = ldr.IsDBNull(1) ? default(Guid) : ldr.GetGuid(1)
}));
}).Invoke(
qr,
qr.DataContext,
dr,
qr.Expression,
qr.Parameters)
Actual:
(qr, dr) => ((
qr,
dctx,
rd,
expr,
ps) =>
{
var ldr = (Issue83_linq2db.SQLiteDataReader)rd;
// Error is here:
// "== Issue83_linq2db.InheritanceTests.TypeCodeEnum.A1" should be applied to ternary operation, not to false value
return (ldr.IsDBNull(0)
? Issue83_linq2db.InheritanceTests.TypeCodeEnum.Base
: (Issue83_linq2db.InheritanceTests.TypeCodeEnum)ldr.GetInt32(0) == Issue83_linq2db.InheritanceTests.TypeCodeEnum.A1)
? (Issue83_linq2db.InheritanceTests.InheritanceA)((Issue83_linq2db.InheritanceTests.InheritanceA1)Issue83_linq2db.TableBuilder.TableContext.OnEntityCreated(
dctx,
new Issue83_linq2db.InheritanceTests.InheritanceA1
{
GuidValue = ldr.IsDBNull(1) ? default(Guid) : ldr.GetGuid(1)
}))
: (Issue83_linq2db.InheritanceTests.InheritanceA)((Issue83_linq2db.InheritanceTests.InheritanceA2)Issue83_linq2db.TableBuilder.TableContext.OnEntityCreated(
dctx,
new Issue83_linq2db.InheritanceTests.InheritanceA2
{
GuidValue = ldr.IsDBNull(1) ? default(Guid) : ldr.GetGuid(1)
}));
}).Invoke(
qr,
qr.DataContext,
dr,
qr.Expression,
qr.Parameters)
Hi, just tried to update to 2.4.0. Without success.
Uninstalling and then installing again shows that i have installed version 2.3.2 - why?
Manage Extensions window shows that i have update from 2.3.2 to 2.4.0.
Maybe there are some ways to cleanup registry or some folders to force installing correct version?
Visualizing types is not working as expected.
MSI file shows that it was created yesterday. But maybe with old content.
VS Professional 2019, Version 16.1.5
Was this tested with the latest VS 2015? Because I see a NullReferenceException.
I found that important brackets are removed when using a ternary operator.
bool someCondition = true;
string trueValue = "hello";
string falseValue = "goodbye";
string someValue = " world";
Expression<Func<string>> expression = () => (someCondition ? trueValue : falseValue) + someValue;
Console.WriteLine(expression.ToReadableString()); /* Prints "() => someCondition ? trueValue : falseValue + someValue" */
The original expression and the printed expression are significantly different and will produce different output.
Func<string> f1 = () => (someCondition ? trueValue : falseValue) + someValue;
Func<string> f2 = () => someCondition ? trueValue : falseValue + someValue;
Console.WriteLine(f1()); /* Prints "hello world" */
Console.WriteLine(f2()); /* Prints "hello" */
There may be other cases where the brackets are important due to the order of operations but this was the first example I tried and found this issue.
Using Visual Studio 2015 with ReadableExpressions v1.9.0.0
at AgileObjects.ReadableExpressions.Translations.TranslationBuffer.WriteToTranslation(String stringValue) at AgileObjects.ReadableExpressions.Translations.StaticTranslators.DefinitionsTranslator.WriteParametersToTranslation(MethodBase method, TranslationBuffer buffer) at AgileObjects.ReadableExpressions.Translations.StaticTranslators.DefinitionsTranslator.Translate(MethodInfo method) at AgileObjects.ReadableExpressions.Visualizers.Core.ExpressionVisualizerObjectSource.GetData(Object target, Stream outgoingData, Action
2 serializer)
at AgileObjects.ReadableExpressions.Visualizers.Vs16ExpressionVisualizerObjectSource.GetData(Object target, Stream outgoingData)
at Microsoft.VisualStudio.DebuggerVisualizers.DebuggeeSide.Impl.ClrCustomVisualizerDebuggeeHost.GetData(Object visualizedObject)`
When I try to visualize the following expression:
{Method = {Boolean lambda_method(System.Runtime.CompilerServices.Closure, Core.Data.Models.Base.EntityBase, Core.Data.Models.Base.EntityBase)}}
for the following delegate signature: Func<EntityBase, EntityBase, bool>
Moreover when I click the visualizer icon on the debugger popup of the delegate, I end up with an empty window that only shows the signature Func<x,y,z>. When I expand that node and visualize the Method (not Target) field of that delegate, I get that exception.
Following up comment on blog post here.
AutoMapper.Mapper.Initialize(cfg =>
{
cfg.AllowNullCollections = true;
cfg.CreateMap<Entity1, Entity1VM>().ReverseMap();
cfg.CreateMap<Entity2, Entity2VM>().ReverseMap();
});
var expression = AutoMapper.Mapper.Configuration.BuildExecutionPlan(typeof(Entity1), typeof(Entity1VM));
expression
has been initialized.Don't really know where to see the resolved expression. Should it be displayed from the Watch window?
Here is what I currently get in Watch window.
Regarding your question from the blog post, the AgileObjects.ReadableExpressions.Visualizers.Vs15.dll
assembly is properly located in C:\Program Files (x86)\Microsoft Visual Studio\2017\Professional\Common7\Packages\Debugger\Visualizers
.
Microsoft Visual Studio Professional 2017
Version 15.2 (26430.6) Release
VisualStudio.15.Release/15.2.0+26430.6
Microsoft .NET Framework
Version 4.6.01586
ReadableExpressions.Visualizers v1.8.6
Hi,
I have two issues, but I'm not sure if ReadableExpressions is supposed to generate working C# code or if the idea is to just generate "human readable" code.
In any case, it would be awesome if there was a way to customize how some things are converted.
The two bugs/issues I ran into are:
obj.X = 5;
where X is a property, will become obj.set_X(5);
Well, it's not really wrong as internally properties are just methods... but it would be cool if there was a setting to get the "expected" format.
Maybe have a setting like ConvertPropertyAccessToDirectSyntax
or something like that.
var formatterExp = Constant(formatterInstance);
Call(formatterExp, deserializeMethod, arg1, arg2, arg3));
becomes:
ReferenceFormatter<MyObject>.Deserialize(arg1, arg2, arg3);
Obviously there's nothing else that ReadableExpressions could use other than the type name in this case.
But there should be something like a callback where I can customize how a Expression.Constant
gets written. Having a simple Func<ConstantExpression, string> customizeConstantToString
as a setting would be awesome.
Hi, is it possible to force using full type names in ToReadableString
? Otherwise we need to add using
sections manually.
Syntax coloring is good, but...
Hi.
I use Microsoft Windows in one language and Microsoft Visual Studio in another one.
After install or update ReadableExpressions, it changes my Visual Studio language to use the "Same as Microsoft Windows".
Thanks.
Reproduced at least with 3.2.2
(qr, dr) => ((
qr,
dctx,
rd,
expr,
ps,
preamble) =>
{
var ldr = (MySqlDataReader)dr;
var anonymousType_Span class="kw">bool</span>_Span class="kw">int</span>_Span class="kw">int</span> = new { IsGroping = (ldr.IsDBNull(0) ? 0 : (int)ldr.GetInt64(0)) == 1, Id1 = ldr.GetInt32(1), Count = (int)ldr.GetInt64(2) };
return anonymousType_Span class="kw">bool</span>_Span class="kw">int</span>_Span class="kw">int</span>;
}).Invoke(
qr,
qr.DataContext,
dr,
qr.Expression,
qr.Parameters,
qr.Preambles)
Hi,
Thanks for great extension. It really helps me in modifying and analyzing expression trees.
But one thing i'm missing. Visual Studio 2019 and previous versions shows in hint very uninformative information for types, especially for complex generic types.
It would be better to see instead of
System.Tuple`2[[Tests.Playground.EagerLoadingTests+MasterClass, linq2db.Tests.Playground, Version=2.6.0.0, Culture=neutral, PublicKeyToken=e41013125f9e410a],[Tests.Playground.EagerLoadingTests+DetailClass, linq2db.Tests.Playground, Version=2.6.0.0, Culture=neutral, PublicKeyToken=e41013125f9e410a]], mscorlib, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089
Shorter version
Tuple<MasterClass, DetailClass>
Also during modification Expression Tree, there are many MakeGenericMethod
calls, so it is also better to show shorter hint for MethodInfo
Instead of
{System.Linq.IQueryable`1[System.Tuple`2[Tests.Playground.EagerLoadingTests+MasterClass,Tests.Playground.EagerLoadingTests+DetailClass]] SelectMany[MasterClass,DetailClass,Tuple`2](System.Linq.IQueryable`1[Tests.Playground.EagerLoadingTests+MasterClass], System.Linq.Expressions.Expression`1[System.Func`2[Tests.Playground.EagerLoadingTests+MasterClass,System.Collections.Generic.IEnumerable`1[Tests.Playground.EagerLoadingTests+DetailClass]]], System.Linq.Expressions.Expression`1[System.Func`3[Tests.Playground.EagerLoadingTests+MasterClass,Tests.Playground.EagerLoadingTests+DetailClass,System.Tuple`2[Tests.Playground.EagerLoadingTests+MasterClass,Tests.Playground.EagerLoadingTests+DetailClass]]])}
More informative version
IQueryable<Tuple<MasterClass, DetailClass>> SelectMany<MasterClass, DetailClass, Tuple<MasterClass, DetailClass>>
(
IQueryable<MasterClass> source,
Expression<Func<MasterClass, IEnumerable<DetailClass>>> collectionSelector,
Expression<Func<MasterClass, DetailClass, Tuple<MasterClass, DetailClass>>> resultSelector
)
I have did MethodInfo
visualization myself using assembly level DebuggerDisplay
[assembly: DebuggerDisplay("{LinqToDB.Common.Internal.MethodInfoExtensions.ShortDisplayName(this)}", Target = typeof(MethodInfo))]
But with no chance to visualize Type
, the following attribute won't work
[assembly: DebuggerDisplay("{LinqToDB.Common.Internal.TypeExtensions.ShortDisplayName(this)}", Target = typeof(Type))]
It is possible to visualize Type
and MethodInfo
using your extension?
Thanks.
It seems like the extension is not working as expected in VS 2017. When I add the expression variable to the watch window and click on the magnifier icon, an error is shown stating that a custom viewer can't be loaded.
I am using VS 2017 version 15.3.5.
I would also recommend providing information on how to access the data from your extension at the page in the marketplace. Also, please provide some indicator that the installation has finished.
Hello, thank you for this great tool!
I started to use it and found following issue:
var from = typeof(string);
var to = typeof(int);
var p = Expression.Parameter(from, "p");
var body = Expression.Condition(
Expression.NotEqual(p, Expression.Constant(null, from)),
Expression.Convert(p, to, to.GetMethod(nameof(int.Parse), new[] { from })),
Expression.Constant(0));
var expr = Expression.Lambda<Func<string, int>>(body, p);
produces following C# code:
p => (p != null) ? (int)p : 0
when it should be
p => (p != null) ? int.Parse(p) : 0
An unhandled exception of type 'System.TypeInitializationException' was thrown by the custom visualizer component in the process being debugged. The type initializer for 'AgileObjects.ReadableExpressions.Visualizers.Core.Configuration.VisualizerDialogSettings' threw an exception.
at AgileObjects.ReadableExpressions.Visualizers.Core.Configuration.VisualizerDialogSettings.GetInstance()
at AgileObjects.ReadableExpressions.Visualizers.Core.ExpressionVisualizerObjectSource.GetDialogSettings()
at AgileObjects.ReadableExpressions.Visualizers.Core.ExpressionVisualizerObjectSource.<>c.<Translate>b__4_0(TranslationSettings settings)
at AgileObjects.ReadableExpressions.ExpressionExtensions.GetTranslationSettings(Func`2 configuration)
at AgileObjects.ReadableExpressions.ExpressionExtensions.ToReadableString(Expression expression, Func`2 configuration)
at AgileObjects.ReadableExpressions.Visualizers.Core.ExpressionVisualizerObjectSource.Translate(Expression expression)
at AgileObjects.ReadableExpressions.Visualizers.Core.ExpressionVisualizerObjectSource.GetTranslationFor(Object target)
at AgileObjects.ReadableExpressions.Visualizers.Core.ExpressionVisualizerObjectSource.GetData(Object target, Stream outgoingData, Action`2 serializer)
at AgileObjects.ReadableExpressions.Visualizers.Vs16ExpressionVisualizerObjectSource.GetData(Object target, Stream outgoingData)
at Microsoft.VisualStudio.DebuggerVisualizers.DebuggeeSide.Impl.ClrCustomVisualizerDebuggeeHost.GetData(Object visualizedObject)```
(This issue affects also visual studio's visualizer)
If visualized expression contains \0 in character/string constant, visualization displays expression only to that point. I suspect that rendered expression doesn't escape it and visual studio window, used for display, treat it as terminating character.
public enum Test
{
One,
Two
}
Expression<Func<bool, bool>> expr = flag => (flag ? Test.One : Test.Two) == Test.Two;
Expected:
flag => (flag ? Test.One : Test.Two) == Test.Two
or
flag => (int)(flag ? Test.One : Test.Two) == 1
Actual:
flag => ((int)flag ? Test.One : Test.Two) == 1
I have tried using the TranslateConstantsUsing option, but it does not seem to change the string. Am I doing something wrong? I was using this code for testing:
expression.ToReadableString(c => c.TranslateConstantsUsing((type, value) => "Hello");
Maybe I didn't understand what this setting is doing. I have an Expression like this: x => x.Property.Equals(value))
and I want to translate the variable name value to the actual value in the variable. How can I translate this value?
An unhandled exception of type 'System.ArgumentOutOfRangeException' was thrown by the custom visualizer component in the process being debugged.
Length cannot be less than zero. (Parameter 'length')
at System.String.Substring(Int32 startIndex, Int32 length)
at AgileObjects.ReadableExpressions.Extensions.PublicTypeExtensions.GetGenericTypeVariableName(String variableName, Type namingType, TranslationSettings settings)
at AgileObjects.ReadableExpressions.Extensions.PublicTypeExtensions.GetVariableName(Type type, TranslationSettings settings)
at AgileObjects.ReadableExpressions.Extensions.PublicTypeExtensions.GetVariableNameInCamelCase(Type type, TranslationSettings settings)
at AgileObjects.ReadableExpressions.Translations.ParameterTranslation.UnnamedParameterTranslation..ctor(ParameterExpression parameter, ITranslationContext context)
at AgileObjects.ReadableExpressions.Translations.ParameterTranslation.For(ParameterExpression parameter, ITranslationContext context)
at AgileObjects.ReadableExpressions.Translations.TranslationTree.GetTranslationFor(Expression expression)
at AgileObjects.ReadableExpressions.Translations.TranslationTree.AgileObjects.ReadableExpressions.Translations.Interfaces.ITranslationContext.GetCodeBlockTranslationFor(Expression expression)
at AgileObjects.ReadableExpressions.Translations.AssignmentTranslation..ctor(BinaryExpression assignment, ITranslationContext context)
at AgileObjects.ReadableExpressions.Translations.TranslationTree.GetTranslationFor(Expression expression)
at AgileObjects.ReadableExpressions.Translations.TranslationTree.AgileObjects.ReadableExpressions.Translations.Interfaces.ITranslationContext.GetTranslationFor(Expression expression)
at AgileObjects.ReadableExpressions.Translations.BlockTranslation.BlockStatementTranslation..ctor(Expression expression, ITranslationContext context)
at AgileObjects.ReadableExpressions.Translations.BlockTranslation.BlockAssignmentStatementTranslation..ctor(BinaryExpression assignment, ITranslationContext context)
at AgileObjects.ReadableExpressions.Translations.BlockTranslation.GetBlockStatements(BlockExpression block, ITranslationContext context, Boolean& hasMultiStatementStatement, Int32& estimatedStatementsSize, Boolean& hasGoto)
at AgileObjects.ReadableExpressions.Translations.BlockTranslation..ctor(BlockExpression block, ITranslationContext context)
at AgileObjects.ReadableExpressions.Translations.TranslationTree.GetTranslationFor(Expression expression)
at AgileObjects.ReadableExpressions.Translations.TranslationTree.AgileObjects.ReadableExpressions.Translations.Interfaces.ITranslationContext.GetCodeBlockTranslationFor(Expression expression)
at AgileObjects.ReadableExpressions.Translations.ConditionalTranslation.TernaryTranslation..ctor(ConditionalExpression conditional, ITranslationContext context)
at AgileObjects.ReadableExpressions.Translations.ConditionalTranslation.For(ConditionalExpression conditional, ITranslationContext context)
at AgileObjects.ReadableExpressions.Translations.TranslationTree.GetTranslationFor(Expression expression)
at AgileObjects.ReadableExpressions.Translations.TranslationTree.AgileObjects.ReadableExpressions.Translations.Interfaces.ITranslationContext.GetCodeBlockTranslationFor(Expression expression)
at AgileObjects.ReadableExpressions.Translations.ConditionalTranslation.TernaryTranslation..ctor(ConditionalExpression conditional, ITranslationContext context)
at AgileObjects.ReadableExpressions.Translations.ConditionalTranslation.For(ConditionalExpression conditional, ITranslationContext context)
at AgileObjects.ReadableExpressions.Translations.TranslationTree.GetTranslationFor(Expression expression)
at AgileObjects.ReadableExpressions.Translations.TranslationTree.AgileObjects.ReadableExpressions.Translations.Interfaces.ITranslationContext.GetTranslationFor(Expression expression)
at AgileObjects.ReadableExpressions.Translations.BlockTranslation.BlockStatementTranslation..ctor(Expression expression, ITranslationContext context)
at AgileObjects.ReadableExpressions.Translations.BlockTranslation.GetBlockStatements(BlockExpression block, ITranslationContext context, Boolean& hasMultiStatementStatement, Int32& estimatedStatementsSize, Boolean& hasGoto)
at AgileObjects.ReadableExpressions.Translations.BlockTranslation..ctor(BlockExpression block, ITranslationContext context)
at AgileObjects.ReadableExpressions.Translations.TranslationTree.GetTranslationFor(Expression expression)
at AgileObjects.ReadableExpressions.Translations.TranslationTree.AgileObjects.ReadableExpressions.Translations.Interfaces.ITranslationContext.GetCodeBlockTranslationFor(Expression expression)
at AgileObjects.ReadableExpressions.Translations.LambdaTranslation..ctor(LambdaExpression lambda, ITranslationContext context)
at AgileObjects.ReadableExpressions.Translations.TranslationTree.GetTranslationFor(Expression expression)
at AgileObjects.ReadableExpressions.Translations.TranslationTree..ctor(Expression expression, TranslationSettings settings)
at AgileObjects.ReadableExpressions.ExpressionExtensions.ToReadableString(Expression expression, Func`2 configuration)
at AgileObjects.ReadableExpressions.Visualizers.Core.ExpressionVisualizerObjectSource.GetData(Object target, Stream outgoingData, Action`2 serializer)
at AgileObjects.ReadableExpressions.Visualizers.Vs16ExpressionVisualizerObjectSource.GetData(Object target, Stream outgoingData)
at Microsoft.VisualStudio.DebuggerVisualizers.DebuggeeSide.Impl.ClrCustomVisualizerDebuggeeHost.GetData(Object visualizedObject)
This translates to
typeMapDestination.Foos =
{
var passedDestination = (dest == null) ? null : typeMapDestination.Foos;
var collectionDestination = (passedDestination != null) ? passedDestination : new List<ComplexTypeMapper.Foo>();
return (resolvedValue == null)
? collectionDestination
: {
var enumerator = resolvedValue.GetEnumerator();
while (true)
{
if (enumerator.MoveNext())
{
var item = enumerator.Current;
collectionDestination.Add(ctxt.Map(item, null));
}
else
{
break;
}
}
return collectionDestination;
return }
}
Opening this issue to track support of the extension for VS 2019 which is currently in Preview 1.
π Hello,
Testing out your debugger visualizer, and I notice it does not install for Visual Studio 2017 Enterprise.
I have 2015 Professional and 2017 Enterprise installed.
The extension appears in the 2015 list and not in the 2017 list.
=== Logging stopped: 9/19/2018 10:54:51 ===
MSI (c) (5C:E8) [10:54:51:283]: Note: 1: 1707
MSI (c) (5C:E8) [10:54:51:283]: Note: 1: 2205 2: 3: Error
MSI (c) (5C:E8) [10:54:51:283]: Note: 1: 2228 2: 3: Error 4: SELECT `Message` FROM `Error` WHERE `Error` = 1707
MSI (c) (5C:E8) [10:54:51:283]: Note: 1: 2205 2: 3: Error
MSI (c) (5C:E8) [10:54:51:283]: Note: 1: 2228 2: 3: Error 4: SELECT `Message` FROM `Error` WHERE `Error` = 1709
MSI (c) (5C:E8) [10:54:51:283]: Product: AgileObjects.ReadableExpressions.Visualizers -- Installation completed successfully.
MSI (c) (5C:E8) [10:54:51:284]: Windows Installer installed the product. Product Name: AgileObjects.ReadableExpressions.Visualizers. Product Version: 1.12.1.0. Product Language: 1033. Manufacturer: AgileObjects. Installation success or error status: 0.
MSI (c) (5C:E8) [10:54:51:284]: Grabbed execution mutex.
MSI (c) (5C:E8) [10:54:51:284]: Cleaning up uninstalled install packages, if any exist
MSI (c) (5C:E8) [10:54:51:285]: MainEngineThread is returning 0
=== Verbose logging stopped: 9/19/2018 10:54:51 ===
Please correct me if I'm wrong, but shouldn't double negation of x yield "-(-x)"?
Instead it returns "--x".
The following statement fails:
Assert.AreEqual(Expression.Negate(Expression.Negate(Expression.Parameter(typeof(double), "x"))).ToReadableString(), "-(-x)");
Extra info: https://gist.github.com/lbargaoanu/0291928f8441c2e6db339c4986fb0a9f
.Net Framework, latest VS
My expression tree is assigning DBNull.Value to a DBParameter.Value property.
DebugView:
.Constant<System.Data.Common.DbParameter>(@d1).Value = .Constant<System.Object>()
ReadableExpressions:
Value = ;
It confuses when the output is not legal C#. Can a placeholder be output where the missing value should go?
I tried using ReadableExpressions to convert an Expression that contains a Func[SomeClass, AnonymousType] to C# code:
expression.Body.ToReadableString(c=>c.NameAnonymousTypesUsing(x=>MyNameFactory(x)))
however, it returns
new {A = x.A, B = x.B}
which, while it is valid code, drops the type information. I'd expect the anonymous type to be presserved and renamed using the factory I provided (which currently is not being called), returning something like this:
new MyClassNameAsGeneratedByMyFactory(){A = x.A, B = x.B}
Is this by design or is it a bug?
Well, Visual Studio 2022 preview is become usable for me. One thing that I have missed is ReadableExpressions
.
Any plans to support?
Thanks!
I have VS 2017 and 2019 and the installer fails with an unspecified error. I have unblocked the msi and bypassed Windows Defender.
v = (a, b) => (a + b)).Invoke(1, 2
Note the missing parenthesis before the lambda and at the end of the Invoke method call.
Minimal example:
var a = Expression.Parameter(typeof(int), "a");
var b = Expression.Parameter(typeof(int), "b");
var body = Expression.Block(Expression.Add(a, b));
var lambda = Expression.Lambda(body, a, b);
var call = Expression.Invoke(lambda, Expression.Constant(1), Expression.Constant(2));
var variable = Expression.Variable(typeof(int), "v");
var assign = Expression.Assign(variable, call);
Console.WriteLine(assign.ToReadableString());
Try to visualize any of these methods.
var methods = typeof(Queryable).GetRuntimeMethods()
.Where(e => e.Name == "SelectMany").ToArray();
Invalid output:
public static IQueryable Queryable.SelectMany
(
IQueryable source,
Expression<FUNC>> selector
)
Same issue with visualizing types.
Version 3.0.1
Expression<Func<string>> expr = ()=>string.Concat("1","2","3","4","5");
expr.ToReadableString().Dump();
I get
() => new[] { "1", "2", "3", "4", "5" }
A declarative, efficient, and flexible JavaScript library for building user interfaces.
π Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.
TypeScript is a superset of JavaScript that compiles to clean JavaScript output.
An Open Source Machine Learning Framework for Everyone
The Web framework for perfectionists with deadlines.
A PHP framework for web artisans
Bring data to life with SVG, Canvas and HTML. πππ
JavaScript (JS) is a lightweight interpreted programming language with first-class functions.
Some thing interesting about web. New door for the world.
A server is a program made to process requests and deliver data to clients.
Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.
Some thing interesting about visualization, use data art
Some thing interesting about game, make everyone happy.
We are working to build community through open source technology. NB: members must have two-factor auth.
Open source projects and samples from Microsoft.
Google β€οΈ Open Source for everyone.
Alibaba Open Source for everyone
Data-Driven Documents codes.
China tencent open source team.