gpt4 book ai didi

c# - 记录 'Lenses' - with 表达式的表达式树

转载 作者:行者123 更新时间:2023-12-02 02:08:47 25 4
gpt4 key购买 nike

有没有办法为新的 with 构建表达式树运算符?

我正在尝试为记录实现“Lens”功能,该功能只需要一个选择器并自动生成更改器(mutator)

我的目标是从“选择器”进行转换:

Expression<Func<T, TMember>> expression (即employee => employee.Name)

致“变异者”:

(employee, newName) => employee with { Name = newName }

我确实设法对上面的简单情况执行此操作,请参阅下面的答案,但这不适用于嵌套情况,即:

record Employee(string Name, int Age);
record Manager(String Name, Employee Employee);

这里我想改变 ie

manager => manager.Employee.Name

(manager, newEmployeeName) => manager with { Employee = manager.Employee with { Name = newEmployeeName}}

有什么帮助吗?

最佳答案

可以处理嵌套属性的

CalcMutator 方法看起来像这样

static Func<T, TMember, T> CalcMutator(Expression<Func<T, TMember>> expression)
{
var typeParam = expression.Parameters.First();
var valueParam = Expression.Parameter(typeof(TMember), "v");

var variables = new List<ParameterExpression>();
var blockExpressions = new List<Expression>();

var property = (MemberExpression)expression.Body;
Expression currentValue = valueParam;
var index = 0;

while (property != null)
{
var variable = Expression.Variable(property.Expression.Type, $"v_{index}");
variables.Add(variable);

var cloneMethod = property.Expression.Type.GetMethod("<Clone>$");
if (cloneMethod is null) throw new Exception($"CalcMutatorNo Clone method on {typeof(T)}");
var cloneCall = Expression.Call(property.Expression, cloneMethod);

var assignClonedToVariable = Expression.Assign(variable, cloneCall);

var accessVariableProperty = Expression.MakeMemberAccess(variable, property.Member);
var assignVariablePropertyValue = Expression.Assign(accessVariableProperty, currentValue);

blockExpressions.Add(assignClonedToVariable);
blockExpressions.Add(assignVariablePropertyValue);

property = property.Expression as MemberExpression;
currentValue = variable;
index++;
}

// Return root object
blockExpressions.Add(currentValue);

var block = Expression.Block(variables, blockExpressions);
var assignLambda = (Expression<Func<T, TMember, T>>)Expression.Lambda(block, typeParam, valueParam);
return assignLambda.Compile();
}

请记住,使用 ImmutableDictionary 实现的 Cache 不是线程安全的。如果您想确保缓存的表达式可以安全地在多线程环境中使用,最好使用 ConcurrentDictionary 进行缓存,或者在 ImmutableDictionary 周围应用一些同步原语.

关于c# - 记录 'Lenses' - with 表达式的表达式树,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/68012124/

25 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com