c# - 强制执行那个 `Expression>` 有一个 Body 是一个 `MemberExpression`
问题描述
public void GiveMeAProp(Expression<Func<TInstance,TProp>> prop)
经常被用作说“请给我一个属性选择器”的标准方式。但是有很多东西可以满足这个签名,但实际上并不是“真正的”属性。例如,以下所有编译。
GiveMeAProp(x => Method());
GiveMeAProp((x) => localVariable);
GiveMeAProp(x => x);
GiveMeAProp(x => (Type)x);
GiveMeAProp((x) => !x.BooleanProp);
我当然可以简单地声明我的方法采用 a MemberExpression
,但随后我失去了表达式的严格类型,特别是失去了编写的能力:
public void SetThisProp(Expression<Func<TInstance,TProp>> prop, TProp value)
我可以在运行时检查我最终得到的表达式的 Body 是 a MemberExpression
,但是如果我可以让类型系统为我强制执行它会非常好?Expression<T>
在我的用例中,实际上没有其他类型的参数是有效的。
问题:无论如何我可以静态强制一个参数代表 aMemberExpression
并且它返回一个 type吗?T
解决方案
Is there anyway that I can enforce statically that an argument represents a MemberExpression and also that it returns a type T?
No, not at present in C#.
It is difficult to prove a negative, but I think it is reasonably clear from all the various libraries which follow the pattern you cite that this is the optimal approach here. If there were a better approach, I think it would have caught on pretty widely by now.
For example, the "OrderBy
" method in Linq is a pretty classic example of a library asking for a property in a typesafe way, as you are doing here, and they haven't managed to avoid the same pitfalls you cite:
public static System.Linq.IOrderedQueryable<TSource> OrderBy<TSource,TKey> (this System.Linq.IQueryable<TSource> source, System.Linq.Expressions.Expression<Func<TSource,TKey>> keySelector);
var studentsOrderByRank = students.OrderBy(w => w.Rank);
The following will compile, but fail at runtime:
string localVar = "example";
var studentsOrderByRank = students.OrderBy(w => localVar);
I think that, so long as your library gives clear error messages at runtime if users pass a Expression<Func<TInstance,TProp>>
which is not in fact a property access, this is the best you can do.
See also this answer for best practices in your library re consuming these expressions.
推荐阅读
- excel - Google 电子表格 - 导出为 excel 后在单元格引用中显示一个空单元格
- python-3.x - 如何将子标签移动到母标签之后?
- sql - 如何在一个视图中使用两个选择语句
- python - 在 python 日志中包含文件和行号,以便在 PyCharm 中单击可以转到源代码行?
- python - Scrappy NameError:未定义名称“null”
- git - 如何将带有 LFS 文件的 git 存储库转移到另一个存储库?
- visualization - vega:我可以使用来自两个数据集的信息创建标记吗?
- guacamole - 在 Guacamole RDP 会话中获取客户端主机名
- macos - 为什么 nginx 运行在 8080 端口而不是 81 端口?
- pulumi - 如何使用 Pulumi 在 ACR 和 AppService 容器之间进行持续部署?