c# - 转换方法签名和修改方法体
问题描述
我正在尝试修改函数的表达式。我想用返回相同值的函数替换函数输入参数。function (Foo foo) { return foo.ToString(); }
这个想法是转换:function(Func<Foo> fooProvider) { return fooProvider().ToString() }
其实我什至不想调用传递给我们的函数,而是直接使用函数体。所以真正的例子没有得到一个Func<Foo>
作为输入,而是一个Expression<Func<Foo>>
.
示例代码可以在下面找到。我假设我现在遇到了一个异常,因为我更改了函数的签名。虽然这正是我想做的。
一些代码:程序
class Program
{
public static void Run()
{
Expression<Func<int, bool>> isOdd = number => (number % 2) == 1;
Expression<Func<string, int>> parseTextToNumber = text => Convert.ToInt32(text);
var vistor = new ReplaceExpressionVisitor(isOdd.Parameters[0], parseTextToNumber.Body);
var result = vistor.Visit(isOdd);
Expression<Func<string, bool>> textRepresentsOddNumber = result as dynamic;
//Expected something like this:
Expression<Func<string, bool>> expectedResult = text => (Convert.ToInt32(text) % 2) == 1;
}
}
访客类
private class ReplaceExpressionVisitor : ExpressionVisitor
{
private readonly Expression _oldValue;
private readonly Expression _newValue;
public ReplaceExpressionVisitor(Expression oldValue, Expression newValue)
{
_oldValue = oldValue;
_newValue = newValue;
}
public override Expression Visit(Expression node)
{
if (node == _oldValue)
return _newValue;
return base.Visit(node);
}
}
和错误信息:
System.InvalidOperationException:'当从'VisitLambda'调用时,重写'System.Linq.Expressions.ParameterExpression'类型的节点必须返回相同类型的非空值。或者,覆盖“VisitLambda”并将其更改为不访问这种类型的孩子。
解决方案
几个小时后,我确实发现了一些有用的东西。
PS:不确定这是否是解决此问题的最通用或最佳解决方案。
using System;
using System.Collections.Generic;
using System.Linq;
using System.Linq.Expressions;
public class Program
{
public static void Run()
{
Expression<Func<int, bool>> isOdd = number => (number % 2) == 0;
Expression<Func<string, int>> parseTextToNumber = text => Convert.ToInt32(text);
var visitor = new ReplaceExpressionVisitor(isOdd.Parameters[0], parseTextToNumber.Body);
var result = Expression.Lambda(visitor.Visit(isOdd.Body), parseTextToNumber.Parameters);
Expression<Func<string, bool>> textRepresentsOddNumber = result as dynamic;
//test:
var code = textRepresentsOddNumber.Compile();
Console.WriteLine(code.DynamicInvoke("0"));//writes false
Console.WriteLine(code.DynamicInvoke("1"));//writes true
}
}
private class ReplaceExpressionVisitor : ExpressionVisitor
{
private readonly Expression _oldValue;
private readonly Expression _newValue;
public ReplaceExpressionVisitor(Expression oldValue, Expression newValue)
{
_oldValue = oldValue;
_newValue = newValue;
}
public override Expression Visit(Expression node)
{
if (node == _oldValue)
return _newValue;
return base.Visit(node);
}
}
推荐阅读
- java - 线程中的对象休眠但随后在另一个位置醒来
- c - bsearch() c 上的比较函数
- mysql - MySQL:如何更改选定的值
- ssl - 传递给 ssl verify_fun 函数的 UserState 变量是什么
- r - 在 r 中使用包含 %in% 和重复函数的逻辑表达式
- c++ - 绘制线条的最佳算法
- java - Spring Boot 2:环境变量宽松绑定
- java - Java 10 (Centos) 上的 RandomAccessFile.setLength 慢得多
- database - Postgresql 为每个唯一的学生 ID 选择前 5 个标记行
- amazon-sqs - SQS FIFO 未按正确顺序发送电子邮件