在遍历表达式时提取实例变量的当前值

2023-11-23

我目前正在尝试编写一些将 C# 表达式转换为文本的代码。

为此,我不仅需要遍历表达式树,还需要评估其中的一小部分 - 以获得局部变量的当前值。

我发现很难用语言来表达,所以这里是伪代码。缺少的部分在第一种方法中:

public class Program
{
    private static void DumpExpression(Expression expression)
    {
        // how do I dump out here some text like:
        //      set T2 = Perform "ExternalCalc" on input.T1
        // I can easily get to:
        //      set T2 = Perform "Invoke" on input.T1
        // but how can I substitute Invoke with the runtime value "ExternalCalc"?
    }

    static void Main(string[] args)
    {
        var myEvaluator = new Evaluator() {Name = "ExternalCalc"};
        Expression<Func<Input, Output>> myExpression = (input) => new Output() {T2 = myEvaluator.Invoke(input.T1)};

        DumpExpression(myExpression);
    }
}

class Evaluator
{
    public string Name { get; set; }  

    public string Invoke(string input)
    {
        throw new NotImplementedException("Never intended to be implemented");
    }
}

class Input
{
    public string T1 { get; set; }
}

class Output
{
    public string T2 { get; set; }
}

我已经开始使用如下代码对此进行调查:

        foreach (MemberAssignment memberAssignment in body.Bindings)
        {
            Console.WriteLine("assign to {0}", memberAssignment.Member);
            Console.WriteLine("assign to {0}", memberAssignment.BindingType);
            Console.WriteLine("assign to {0}", memberAssignment.Expression);

            var expression = memberAssignment.Expression;
            if (expression is MethodCallExpression)
            {       
                var methodCall = expression as MethodCallExpression;
                Console.WriteLine("METHOD CALL: " + methodCall.Method.Name);
                Console.WriteLine("METHOD CALL: " + expression.Type.Name);
                var target = methodCall.Object;

                // ?
            }
        }

但是一旦我到达 MethodCallExpression 级别,我就会对如何解析它并获取实际实例感到有点迷失。

非常感谢任何关于如何做到这一点的指示/建议。


解析表达式树...复杂且耗时。这是一个非常不完整几乎可以处理您的示例的版本。特别要注意的是,我们需要:

  • 硬编码到 Evaluator,因为“ExternalCalc”不是表达式的一部分
  • 手动评估一些树

Output:

新的输出将 T2 设置为:调用ExternalCalc,从 capture-context 获取 myEvaluator,输入 = 从 @input 获取 T1

Code:

private static void DumpExpression(Expression expression)
{
    var sb = new StringBuilder();
    Walk(expression, sb);
    string s = sb.ToString();      
}
static object Evaluate(Expression expr)
{
    switch (expr.NodeType)
    {
        case ExpressionType.Constant:
            return ((ConstantExpression)expr).Value;
        case ExpressionType.MemberAccess:
            var me = (MemberExpression)expr;
            object target = Evaluate(me.Expression);
            switch (me.Member.MemberType)
            {
                case System.Reflection.MemberTypes.Field:
                    return ((FieldInfo)me.Member).GetValue(target);
                case System.Reflection.MemberTypes.Property:
                    return ((PropertyInfo)me.Member).GetValue(target, null);
                default:
                    throw new NotSupportedException(me.Member.MemberType.ToString());
            }
        default:
            throw new NotSupportedException(expr.NodeType.ToString());
    }
}
static void Walk(Expression expr, StringBuilder output)
{
    switch (expr.NodeType)
    {
        case ExpressionType.New:
            var ne = (NewExpression)expr;
            var ctor = ne.Constructor;
            output.Append(" a new ").Append(ctor.DeclaringType.Name);
            if(ne.Arguments != null && ne.Arguments.Count != 0)
            {
                var parameters = ctor.GetParameters();
                for(int i = 0 ;i < ne.Arguments.Count ; i++)
                {
                    output.Append(i == 0 ? " with " : ", ")
                          .Append(parameters[i].Name).Append(" =");
                    Walk(ne.Arguments[i], output);
                }                    
            }
            break;
        case ExpressionType.Lambda:
            Walk(((LambdaExpression)expr).Body, output);
            break;
        case ExpressionType.Call:
            var mce = (MethodCallExpression)expr;

            if (mce.Method.DeclaringType == typeof(Evaluator))
            {
                object target = Evaluate(mce.Object);
                output.Append(" call ").Append(((Evaluator)target).Name);
            }
            else
            {
                output.Append(" call ").Append(mce.Method.Name);
            }
            if (mce.Object != null)
            {
                output.Append(" on");
                Walk(mce.Object, output);
            }
            if (mce.Arguments != null && mce.Arguments.Count != 0)
            {
                var parameters = mce.Method.GetParameters();
                for (int i = 0; i < mce.Arguments.Count; i++)
                {
                    output.Append(i == 0 ? " with " : ", ")
                            .Append(parameters[i].Name).Append(" =");
                    Walk(mce.Arguments[i], output);
                }
            }
            break;
        case ExpressionType.MemberInit:
            var mei = (MemberInitExpression)expr;
            Walk(mei.NewExpression, output);
            foreach (var member in mei.Bindings)
            {
                switch(member.BindingType) {
                    case MemberBindingType.Assignment:
                        output.Append(" set ").Append(member.Member.Name)
                            .Append(" to:");
                        Walk(((MemberAssignment)member).Expression, output);
                        break;
                    default:
                        throw new NotSupportedException(member.BindingType.ToString());
                }

            }
            break;
        case ExpressionType.Constant:
            var ce = (ConstantExpression)expr;
            if (Attribute.IsDefined(ce.Type, typeof(CompilerGeneratedAttribute)))
            {
                output.Append(" capture-context");
            }
            else
            {
                output.Append(" ").Append(((ConstantExpression)expr).Value);
            }
            break;
        case ExpressionType.MemberAccess:
            var me = (MemberExpression)expr;
            output.Append(" get ").Append(me.Member.Name).Append(" from");
            if (me.Expression == null)
            { // static
                output.Append(me.Member.DeclaringType.Name);
            }
            else
            {
                Walk(me.Expression, output);
            }
            break;
        case ExpressionType.Parameter:
            var pe = (ParameterExpression)expr;
            output.Append(" @").Append(pe.Name);
            break;
        default:
            throw new NotSupportedException(expr.NodeType.ToString());
    }
}
本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

在遍历表达式时提取实例变量的当前值 的相关文章

随机推荐

  • 如何使用 Visual Studio 加载项打开 TFS 变更集详细信息对话框视图?

    我在 TFS 中有一个特定的工件 例如变更集 123 它具有 URI vstfs VersionControl Changeset 123 我意识到链接 http tfs 8080 tfs web UI Pages Scc ViewChan
  • 如何跨域postMessage?

    的文档发布消息意味着跨域消息传递是可能的 然而 When the popup has fully loaded if not blocked by a popup blocker 这不是一个非常清楚的注释how真正做到这一点 想象一下两个网
  • 每个会话的 NH 请求 - “会话已关闭!”

    NHibernate版本 2 1 我正在使用似乎非常标准的 HttpModule 方法来在 ASP NET NHibernate 应用程序中实现每个请求会话 我正在尝试利用杠杆WebSessionContext 但它似乎无法正常工作 具体来
  • 如何通过按下 NSButton 来显示键盘?

    我只知道在 iOS 上显示键盘的几种方法 触摸文本字段 搜索栏 文本视图 是否可以通过触摸按钮来显示键盘 如果按钮没有标题或可以重命名 我希望可以使用这种方式设置按钮标题 谢谢各位 您需要添加一个UITextField查看您的视图 然后致电
  • 如何使用 FParsec 解析注释

    我正在尝试使用 FParsec 从 s 表达式语言解析 lisp 风格的注释 我在上一个线程中解析单行注释时得到了一些帮助 如何转换 FParsec 解析器来解析空格 虽然这个问题已经解决 但我仍然需要解析多行注释 这是当前的代码 Read
  • 使用 GUID 的一部分作为 ID

    我正在开发 ASP Net MVC 应用程序 我的行动之一需要id作为参数 例如 public actionresult Detail Guid id return View 正如你所看到的 我正在使用Guid代替Int 这个问题更具装饰性
  • 是否可以知道哪些 SciPy / NumPy 函数在多个内核上运行?

    我试图明确找出 SciPy NumPy 中的哪些函数在多个处理器上运行 我可以例如在 SciPy 参考手册中读到 SciPy 使用了这个 但我更感兴趣的是到底哪些函数确实运行并行计算 因为并非所有函数都这样做 理想的情况当然是当您键入 he
  • GHCi 中的功能非详尽模式

    我想创建一个显示列表最后一个元素的函数 这是我的代码 ghci gt let myLast a gt a ghci gt let myLast error ghci gt let myLast x x ghci gt let myLast
  • “重新打开上次关闭的选项卡”导致显示上次 ajax 请求内容

    我正在使用 HTML 5 历史 api 在 ajax 请求发生时保存状态 并且如果用户请求没有 ajax 请求的同一页面 我会提供完整的 html 内容 浏览器的 重新打开最后关闭的选项卡 功能会带来最后的 ajax 请求内容 而无需访问服
  • 为什么错误处理在 Nodemailer 中不起作用?

    我正在尝试使用 nodemailer 设置一个非常简单的联系表单 它工作正常 但我的问题是它不处理错误 如果引发错误 页面应该重定向 但重定向不会发生并且应用程序停止运行 我一生都无法弄清楚为什么会发生这种情况 这是我的代码 if req
  • d3.js:有限制的平移

    我正在研究具有平移功能的基本线性图表 我设法通过限制图表元素的拖动范围d3 event translate values var tx Math max 0 d3 event translate 0 ty Math min 0 d3 eve
  • 创建 Hermetic Maven 构建

    我正在尝试创建一种可以实现密封构建的方法 同时仍然依赖于项目中的 SNAPSHOT 依赖项 出于示例的目的 假设我有一个项目 其依赖结构如下 other 1 2 SNAPSHOT mine 1 2 3 thing 3 1 SNAPSHOT
  • 在 PyQT5 中创建自定义小部件

    我想知道如何在 pyqt 中创建自定义小部件 我见过许多不同的 C 示例 以及一些 pyqt 的非描述性示例 但没有任何内容真正解释如何执行和实现它 特别是没有任何示例基本上不仅仅是修改后的 qt designer 输出 而且我正在从头开始
  • 如何从 HttpClient 响应访问标头? (角/离子)

    我使用的登录端点返回不记名令牌作为响应标头 正如我在 网络 Chrome 检查窗口中看到的那样 Response Headers Access Control Allow Credentials true Access Control Al
  • 向 TIdHttp 请求添加自定义标头,标头值包含逗号

    我正在使用 Delphi XE2 和 Indy 10 5 8 0 我有一个 TIdHttp 实例 我需要向请求添加自定义标头 标头值中包含逗号 因此它会自动解析为多个标头 我不希望它这样做 我需要自定义标头的标头值仍然是一个字符串 而不是根
  • 在基于Web的Spring范围中使用Thymeleaf处理HTML文件并将处理后的模板存储为字符串

    我正在尝试使用 thymeleaf 渲染 HTML 文件 并将生成的 HTML 内容保存在 String 变量中web based scopes of Spring这样我以后就可以用它来发送电子邮件或将内容转换为 pdf 我已经完成了中给出
  • 查找字符串中最短的重复模式

    我想知道是否有办法在 Octave Matlab 中进行模式匹配 我知道 Maple 10 有执行此操作的命令 但不确定我需要在 Octave Matlab 中做什么 所以如果一个数字是12341234123412341234模式匹配将是1
  • 为什么 &[T] 参数也接受 &Vec

    我正在阅读 Rust 书 即迷你grep项目 在那里我遇到了以下片段 fn main let args Vec
  • 计算文件中单词数的最简单方法

    我正在尝试以最简单的方式编写一个程序来计算 Scala 语言文件中单词出现的次数 到目前为止我有这些代码 import scala io Codec string2codec import scala io Source import sc
  • 在遍历表达式时提取实例变量的当前值

    我目前正在尝试编写一些将 C 表达式转换为文本的代码 为此 我不仅需要遍历表达式树 还需要评估其中的一小部分 以获得局部变量的当前值 我发现很难用语言来表达 所以这里是伪代码 缺少的部分在第一种方法中 public class Progra