我正在尝试构建具有不同输入参数类型的表达式字典。我正在尝试存储参数的类型,因为稍后我计划使用 Reflection 来发现该类型的方法。以下是创建字典的代码,以及我创建的用于向其添加条目的通用 Add 函数:
public class LoadEntityQuery : IQuery<LoadEntityQueryResult>
{
public IDictionary<Type, Expression<Func<Type, bool>>> Entities { get; set; }
public LoadEntityQuery()
{
Entities = new Dictionary<Type, Expression<Func<Type, bool>>>();
}
public void Add<T>(Expression<Func<T, bool>> where = null) where T : Entity
{
Expression<Func<Type, bool>> _lambda = null;
if (where != null)
{
ParameterExpression param = Expression.Parameter(typeof(T), where.Parameters[0].Name);
var body = Expression.Invoke(where, param);
_lambda = Expression.Lambda<Func<Type, bool>>(body, param);
}
Entities.Add(typeof(T), _lambda);
}
}
正确创建新方法的主体。问题是当我尝试使用传入的表达式的类型创建新的 Lambda 表达式时,我收到此错误:
类型为"TestNamespace.TestClass"的参数表达式不能用于类型为"System.Type"的委托参数
有人知道我在这种情况下能做什么吗?就像我之前说的,稍后我将遍历这个字典,对每个条目进行一些反思性编程。如果有更好的方法可以做到这一点,我全听着。
作为我正在尝试执行的操作的一个例子,我存储了需要初始化的 POCO 对象的 Where 子句的表达式:
LoadEntityQuery _query = new LoadEntityQuery();
_query.Add<PayrollLocation>();
_query.Add<PayrollGroupBU>();
_query.Add<PersonnelPosition>(t => t.DataSet == MasterDataSet);
_query.Add<EmployeeStatus>();
_query.Add<PayrollGrade>();
此实体列表对于每个应用都是不同的。这个想法是收集所有实体和每个实体的 Where 子句,并使用对每个实体的反射来发现某种方法。(例如,PayrollLocation有一个GetPayrollLocationsQuery()方法,PayrollGroupBU有一个GetPayrollGroupBUQuery()方法...)。Add 方法是通用的,以便我在调用代码中使用 lambda 表达式。
谢谢杰森
仔细查看您的代码,您生成的表达式存在一些问题。 请参阅我在此答案顶部的解释来解释其中之一,这是相同的问题。 您正在创建一个新的 lambda,其中您在此处创建的参数实例不会在正文中使用。
更大的问题是,你的表达对于你似乎试图做的事情来说是错误的。 据我所知,您只是在尝试创建从实体类型到接受该类型实体并返回布尔值的函数的映射。 Type -> Expression<Func<TEntity, bool>>
. 您构建的表达式不起作用。
您应该使字典存储非通用 lambda,这样您就可以轻松存储这些函数,而无需执行转换或重建表达式。 您将无法在此处将它们存储为通用 lambda。 然后在访问它们时强制转换为通用 lambda。 我会把它放在一个单独的类中来管理强制转换并将你的代码重构为这样:
// add all necessary error checking where needed and methods
public class EntityPredicateDictionary
{
private Dictionary<Type, LambdaExpression> dict = new Dictionary<Type, LambdaExpression>();
public Expression<Func<TEntity, bool>> Predicate<TEntity>() where TEntity : Entity
{
return (Expression<Func<TEntity, bool>>)dict[typeof(TEntity)];
}
public LambdaExpression Predicate(Type entityType)
{
return dict[entityType];
}
internal void Add<TEntity>(Expression<Func<TEntity, bool>> predicate) where TEntity : Entity
{
dict.Add(typeof(TEntity), predicate);
}
}
public class LoadEntityQuery : IQuery<LoadEntityQueryResult>
{
public EntityPredicateDictionary Entities { get; private set; }
public LoadEntityQuery()
{
Entities = new EntityPredicateDictionary();
}
public void Add<TEntity>(Expression<Func<TEntity, bool>> predicate = null) where TEntity : Entity
{
Entities.Add(predicate);
}
}
// then to access the predicates
LoadEntityQuery query = ...;
var pred1 = query.Entities.Predicate<Entity1>();
var pred2 = query.Entities.Predicate(typeof(Entity2));
我认为这不会做你期望它做的事情; Func<Type, bool>
定义了一个函数,该函数将类型作为参数并返回布尔值。 Func<T, bool>
定义了一个函数,该函数将 T 类型的对象作为参数并返回布尔值。 字典中定义的 lambda 永远不会接收您尝试过滤的对象,只会接收其类型。
对我来说,以任何适当的方式使其合适的最快方法是使 LoadEntityQuery 类在您期望函数接受的参数类型上泛型,但这可能会在其他方面限制您......
您可以使用一个对象并投射它... 不是最好的解决方案,但至少它封装了铸件并且是一个相当小的零件,同时仍然允许您做在我看来您需要做的事情。
public class LoadEntityQuery : IQuery<LoadEntityQueryResult>
{
// Note: Hide this, we don't want anyone else to have to think about the cast.
private IDictionary<Type, object> Entities { get; set; }
public void Add<T>(Expression<Func<T, bool>> where = null) where T : Entity
{
Entities.Add(typeof(T), where);
}
public Expression<Func<T, bool>> Retrieve<T>() where T : Entity
{
if (!Entities.ContainsKey(typeof(T)))
return null;
return (Expression<Func<T, bool>>)Entities[typeof(T)];
}
}