c# - 强制 `Expression<Func<TInstance,TProp>>` 有一个 Body 是 `MemberExpression`

标签 c# generics reflection expression

public void GiveMeAProp(Expression<Func<TInstance,TProp>> prop)

通常用作“请给我一个属性选择器”的标准表达方式。但是有很多东西可以满足这个签名但实际上并不是“真实”的属性(property)。例如以下全部编译。

GiveMeAProp(x => Method());
GiveMeAProp((x) => localVariable);
GiveMeAProp(x => x);
GiveMeAProp(x => (Type)x);
GiveMeAProp((x) => !x.BooleanProp);

我当然可以简单地声明我的方法采用 MemberExpression , 但后来我失去了表达的严格类型,特别是失去了写作的能力:

public void SetThisProp(Expression<Func<TInstance,TProp>> prop, TProp value)

我可以在运行时检查我得到的表达式是否有一个 MemberExpression 的 Body ,但如果我可以让类型系统为我强制执行它,那真的很好吗?没有其他类型的Expression<T>在我的用例中实际上是一个有效的论点。

问题:无论如何我都可以静态地强制一个参数代表一个MemberExpression并且它返回一个类型 T ?

最佳答案

Is there anyway that I can enforce statically that an argument represents a MemberExpression and also that it returns a type T?

不,目前不在 C# 中。

很难证明是否定的,但我认为从所有遵循您引用的模式的各种库中可以清楚地看出这是这里的最佳方法。如果有更好的方法,我认为它现在应该已经广泛流行了。

例如," OrderBy " method in Linq是库以类型安全的方式请求属性的一个非常经典的例子,正如您在这里所做的那样,他们没有设法避免您引用的相同陷阱:

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);

以下将编译,但在运行时失败:

string localVar = "example";
var studentsOrderByRank = students.OrderBy(w => localVar);

我认为,只要您的库在用户传递 Expression<Func<TInstance,TProp>> 时在运行时给出明确的错误消息这实际上不是属性(property)访问,这是您能做的最好的事情。

另见 this answer在您的库中重新使用这些表达式的最佳实践。

关于c# - 强制 `Expression<Func<TInstance,TProp>>` 有一个 Body 是 `MemberExpression`,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/58914070/

相关文章:

c# - 无法使用 C# 中的轨迹栏更改音频位置

typescript - 从装饰器访问泛型类的静态成员

java - 如何实现一个消息发送系统?

java - 如何迭代java类并使用hashmap来选择正确的方法?

c# - 使用 lambda 表达式创建带反射的对象

Python代码反射与修改

c# - 具有可移植类库的部分类

c# - WPF DataGrid 删除 SelectedItems

c# - 如何使用反射调用泛型方法?

c# - API 测试的测试自动化