表达式树上的ToString产生格式错误的输出 [英] ToString on Expression Trees produces badly formatted output

查看:235
本文介绍了表达式树上的ToString产生格式错误的输出的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

当我使用Expression.ToString()将表达式树转换为人类可读的形式时,结果是这样的:

When I use Expression.ToString() to convert an Expression Tree into human readable form, the result is something like this:

x => ((x.ID > 2) OrElse (x.ID != 6))
x => ((x.ID > 2) AndAlso (x.ID != 6))

理想情况下,我希望输出显示运算符,而不是"OrElse"和"AndAlso":

Ideally, I would want the output to show the operators instead of "OrElse" and "AndAlso":

x => ((x.ID > 2) || (x.ID != 6))
x => ((x.ID > 2) && (x.ID != 6))

作为一种解决方法,我可以使用string.Replace()方法.

As a workaround, I could use the string.Replace() method..

.Replace("AndAlso", "&&")
.Replace("OrElse", "||")

但是这有明显的弱点,而且看起来很尴尬. 另外,我不想创建大的替换"部分或大的正则表达式树只是为了正确设置格式.

but that has obvious weaknesses and seems awkward. Also I do not want to create a large 'Replace'-section or huge regex-tree simply to get the formatting right.

是否有一种简单的方法来获得类似于代码的人类可读形式的表达式树?

Is there a simple way to get a code-like human-readable form of expression trees?

推荐答案

当我对表达式表示的代码的语义感兴趣,而不是确切的语法树时,我已经发现将其编译为Assembly并在ILSpy中查看非常有用.便捷方法:

When I'm interested in the semantics of the code represented by the expression, rather than the exact syntax tree, I've found it very useful to compile it to an Assembly and view that in ILSpy. Convenience method:

// Code is probably adapted from some other answer, don't remember
public static void CompileToAssemblyFile(
  this LambdaExpression expression,
  string outputFilePath = null,
  string assemblyAndModuleName = null,
  string typeName = "TheType",
  string methodName = "TheMethod",
  // Adjust this
  string ilSpyPath = @"C:\path\to\ILSpy.exe")
{
  assemblyAndModuleName = assemblyAndModuleName ?? nameof(CompileToAssemblyFile);

  outputFilePath = outputFilePath ??
                   Path.Combine(
                     Path.GetTempPath(),
                     $"{assemblyAndModuleName}_{DateTime.Now:yyyy-MM-dd_HH_mm_ss}_{Guid.NewGuid()}.dll");

  var domain = AppDomain.CurrentDomain;
  var asmName = new AssemblyName {Name = assemblyAndModuleName};

  var asmBuilder = domain.DefineDynamicAssembly(
    asmName,
    AssemblyBuilderAccess.RunAndSave,
    Path.GetDirectoryName(outputFilePath));

  string outputFileName = Path.GetFileName(outputFilePath);

  var module = asmBuilder.DefineDynamicModule(
    assemblyAndModuleName,
    outputFileName,
    true);

  var typeBuilder = module.DefineType(typeName, TypeAttributes.Public);

  var methodBuilder = typeBuilder.DefineMethod(
    methodName,
    MethodAttributes.Public | MethodAttributes.Static,
    expression.ReturnType,
    expression.Parameters.Select(p => p.Type).ToArray());

  var pdbGenerator = DebugInfoGenerator.CreatePdbGenerator();

  expression.CompileToMethod(methodBuilder, pdbGenerator);

  typeBuilder.CreateType();

  asmBuilder.Save(outputFileName);

  Process.Start(ilSpyPath, outputFilePath);
}

(这对语法树不是很忠实,因为它同时经历了LambdaCompiler完成的Expression-> IL转换以及ILSpy进行的IL-> C#反编译.进入循环,并生成实际的C#.)

(This is not very faithful to the syntax tree because it goes through both the Expression -> IL translation done by the LambdaCompiler, and the IL -> C# decompilation by ILSpy. OTOH, it can improve readability by converting some gotos into loops, and by producing actual C#.)

如果Expression包含非平凡常量"(活动对象),则此操作将失败;但是为此,可以编写一个访客,用新变量替换常量,然后在顶层进行lambda抽象化.

This will fail if the Expression contains "non-trivial constants" (live objects); but for that one could write a visitor that replaces constants by new variables and then lambda-abstracts these variables at the toplevel.

这篇关于表达式树上的ToString产生格式错误的输出的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆