【发布时间】:2018-06-09 06:21:01
【问题描述】:
我有以下界面:
public interface IHasSchoolId
{
long? SchoolId { get; set; }
}
和以下实体:
public class Student : IHasSchoolId
{
long? SchoolId { get; set; }
}
然后有以下实体管理器实现空接口IEntityManager<T>:
public class HasSchoolIdManager: IEntityManager<IHasSchoolId>
{
public static Expression<Func<IHasSchoolId, bool>> Filter()
{
return x=> x.SchoolId != null; //this is just an example
}
}
最后我有以下方法:
private Expression<Func<TEntity, bool>> GetFilters<TEntity>()
{
Expression<Func<TEntity, bool>> result = null;
var entityManagers = //geting entitymanagers that are assinable to TEntity, like the one above and a lot more like IEntityManager<Student> itself
foreach (var entityManager in entityManagers)
{
var filterMethod = entityManager.GetMethod("Filter");
if (filterMethod != null)
result = AndAlso(result, (Expression<Func<TEntity, bool>>) filterMethod.Invoke(null, null)); //this line throws exception
}
return result;
}
然后当我调用GetFilters<Student>() 之类的方法时,我得到以下异常:
System.InvalidCastException:'无法转换类型为 'System.Linq.Expressions.Expression[System.Func[WebCore.Models.Infrastructure.Interfaces.IHasSchoolId,System.Boolean]] 的对象'输入'System.Linq.Expressions.Expression[System.Func[WebCore.Models.Student,System.Boolean]]'。'
顺便说一句,这是我的 AndAlso 方法,效果很好:
private Expression<Func<T, bool>> AndAlso<T>(
Expression<Func<T, bool>> expr1,
Expression<Func<T, bool>> expr2)
{
if (expr1 == null)
return expr2;
if (expr2 == null)
return expr1;
ParameterExpression param = expr1.Parameters[0];
if (ReferenceEquals(param, expr2.Parameters[0]))
{
return Expression.Lambda<Func<T, bool>>(
Expression.AndAlso(expr1.Body, expr2.Body), param);
}
return Expression.Lambda<Func<T, bool>>(
Expression.AndAlso(
expr1.Body,
Expression.Invoke(expr2, param)), param);
}
这是我的空 IEntityManager 界面:
public interface IEntityManager<T>
{
}
注意:并不是我所有的实体都实现了IHasSchoolId接口,还有很多其他的接口,这只是一个例子
我想我的问题是,如何从 Expression<Func</*an interface*/, bool>> 转换为 Expression<Func</*a class that implements that interface*/, bool>>
使用反射,因为如您所见,我使用反射调用过滤器方法
【问题讨论】:
-
请出示
IEntityManager界面 -
我不确定您要实现什么,并且您没有显示管理器界面的代码(我知道它是空的,但仍然需要),所以我假设您定义了它与界面。相反,请尝试使管理器接口通用并将其限制为接口,例如
public interface IEntityManager<TEntity> where TEntity : IHasSchoolId。 -
请贴出引发异常的代码行。
-
@JohnWu 他已经做到了。方法见代码中的 cmets(需要向右滚动才能看到)。
-
@user4111079 你找到解决方案了吗?我也在搜索完全相同的代码,就像这样
public class FilterQueryable { public Expression<Func<IHasCreator, bool>> forCurrentUser; public FilterQueryable(UserValues userValues) { forCurrentUser = p => p.CreatorId == userValues.Identifier; } }
标签: c# reflection lambda casting