我正在尝试构建具有不同输入参数类型的表达式字典。我试图存储参数的类型,因为后来我计划使用Reflection来发现类型的方法。下面是创建字典的代码和我创建的通用添加函数,用于向其添加条目:
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'的ParameterExpression不能用于'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表达式。
谢谢, 杰森
答案 0 :(得分:4)
仔细查看代码,您生成的表达式存在一些问题。请参阅this answer顶部的解释来解释其中一个问题,这是同一个问题。您正在创建一个新的lambda,其中您在此处创建的参数实例未在正文中使用。
更大的问题是你的表达对于你似乎想要做的事情是错误的。据我所知,你只是想创建一个从实体类型到带有该类型实体并返回bool的函数的映射。 Type -> Expression<Func<TEntity, bool>>
。你构建的表达式不起作用。
您应该使字典存储非通用lambda,这样您就可以轻松存储这些函数,而无需执行转换或重建表达式。您将无法将它们存储为通用lambdas。然后在访问它时转换为通用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));
答案 1 :(得分:0)
我认为这不会像你期望的那样做; Func<Type, bool>
定义了一个函数,它将一个类型作为参数并返回一个bool。 Func<T, bool>
定义了一个函数,该函数将类型为T的对象作为参数并返回bool。字典中定义的lambda永远不会接收您尝试过滤的对象,只接收它的类型。
对我而言,以最合适的方式实现这一点的最快方法是使LoadEntityQuery类对您希望函数接受的参数类型具有通用性,但这可能会以其他方式限制您... < / p>
你可以使用一个物体并施放它......不是最好的解决方案,但至少它封装了铸件并且是一个相当小的部分,同时仍然允许你做你需要做的事情。< / p>
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)];
}
}