概念: ExpressionLens<A, B>
作者: WorldMaker创建于 2026年4月3日更新于 2026年4月3日
在考虑 Lens<A, B> 这个概念时,在使用 EF 或类似的语言(也许甚至是一个支持表达式编译的世界Eff supports Expression compilation)的上下文中,一个相对纯粹的子类 ExpressionLens<A, B> 可能会很有用。大致上可以这样写(未经过测试):
using System.Linq.Expression;
public readonly struct ExpressionLens<A, B>(
public readonly Expression<Func<A, B>> GetExp,
public readonly Expression<Func<B, Expression<Func<A, A>> SetExp)
: Lens(GetExp.Compile(), b => SetExp.Compile().Invoke(b).Compile());这种做法的好处是,可以在 Linq 上下文中重用相同的底层 Lens,例如在使用 EF 查询时,可以使用 .Select(MyExpressionLens.GetExp),而 EF 在许多情况下可以将其转换为数据库投影。 (在脑海中,我无法想到一个好的 Linq 示例来表示 SetExp,但肯定有。此外,用这种方式编写嵌套的表达式可能会很难可靠地编译,因此可能是 YAGNI,并且只提供 GetExp。) 它可能仍然是 Lens 的子类,而不是默认类,原因是 C# 编译器只会将 Func<A, B> 的一部分编译为 Expression<Func<A, B>>。在使用 Lens 的场景中,您可能不需要这些限制。此外,也可能需要更复杂的工作来支持 Prelude.lens(ExpressionLens<A, B>, ExpressionLens<B, C>) 的特化,该特化还可以返回 ExpressionLens<A, C>,但如果存在该特化,则可以为 ExpressionLens 的子类提供额外的理由。在某些查询场景中,.Select(lens(MyExpressionLens, MySubPropertyExpressionLens).GetExp) 可能会很有用。
内容来源: louthy/language-ext