我有一个包含一些通用方法的存储库类。一个是
public IEnumerable<T> FindAll<T>(Expression<Func<T, bool>> predicate) where T : class
{
return GetDbSet<T>().Where(predicate);
}
对于单元测试,我有一个TestRepository
,它使用内存中的对象而不是数据库。 TestRepository
会覆盖FindAll
方法,我想控制返回的内容。所以我希望能够做到这样的事情:
public override IEnumerable<T> FindAll<T>(Expression<Func<T, bool>> predicate)
{
return MyEntities.Where(predicate).Cast<T>();
}
但MyEntities.Where()
只接受Expression<Func<MyEntity, bool>>
。
如何将通用表达式转换/转换为强类型表达式?
答案 0 :(得分:1)
你可以这样做。不确定它是否是一个好主意,但它确实有效。基本上,您的重载可以将类型参数T
与您的实体类进行比较。如果谓词具有正确的类型,则可以进行强制转换。否则,你没有任何东西可以归还。
public class MyEntity { public int x; }
MyEntity[] MyEntitiesList = Enumerable.Range(1,5).Select(y => new MyEntity() { x = y }).ToArray();
public IEnumerable<T> FindAll<T>(Expression<Func<T, bool>> predicate)
{
if (typeof(T) == typeof(MyEntity))
{
return (IEnumerable<T>)MyEntitiesList.Where((predicate as Expression<Func<MyEntity, bool>>).Compile());
}
return new T[0];
}
用法:
var res = FindAll((MyEntity y) => y.x % 2 == 0).ToList();
Console.WriteLine(res.Count);
答案 1 :(得分:0)
看起来您的存储库实现存在一个主要缺陷,即调用者不知道他只能传递某些类型的参数(例如,它看起来像我可以FindAll<int>(v => v > 0)
但实际上是底层实现仅适用于MyEntity
)。换句话说,它试图太“聪明”,它不直观且容易出错。
解决这个问题的一种方法是引入一个接口/基类:
public interface IRepository<T>
{
IEnumerable<T> FindAll<T>(Expression<Func<T, bool>> predicate);
}
// A base class that can carry helper functionality.
public abstract class Repository<T> : IRepository<T>
{
private readonly IEnumerable<T> _entities;
protected Repository(IEnumerable<T> entities)
{
_entities = entities;
}
public IEnumerable<T> FindAll(Expression<Func<T, bool>> predicate)
{
return _entities.Where(predicate);
}
}
// Concrete implementation
public class MyEntityRepository : Repository<MyEntity>
{
public MyEntityRepository() : base(new MyDbContext().MyEntities) { }
}
在上面的例子中,我指的是MyDbContext
仅用于演示目的(如果你使用Entity Framework,它看起来会更熟悉。)
现在您可以实例化MyEntityRepository
并在整个应用程序中使用它。如果你正在使用某种IoC,你可以稍微修改一下代码:
public interface IMyEntityRepository : IRepository<MyEntity>
{
// ...
}
public class MyEntityRepository : Repository<MyEntity>, IMyEntityRepository
{
// ...
}
现在,您可以轻松地在应用程序中注入和模拟IMyEntityRepository
。
希望这有帮助。
<强>更新强>
事实证明,由于给定的实现仅用于测试目的,您可以尝试以下列方式生成所需类型的表达式:
return MyEntities.Where(Expression.Lambda<Func<MyEntity, bool>>(predicate.Body,
predicate.Parameters)).Cast<T>();
如果需要显式的那个,你也可以对lambda参数应用一些强制转换。