我有一个通用的Repo
类,它公开了一个数据库LINQ提供程序:
class Repo<T> where T : IPersisted
{
IQueryable<T> Get()
{
return _queryable;
}
}
(IPersisted
是持久化对象的简单标记接口)。
现在..。我希望找到一种为某些派生类型的IPersisted
注入默认LINQ表达式的优雅方法。例如,对于以下IPersisted实现:
class Deletable : IPersisted
{
bool IsDeleted { get; set; }
}
我希望IQueryable<T> Get()
方法返回_queryable.Where(q => !q.IsDeleted)
,只有在T
类型为Deletable
时才返回。
我考虑创建某种类型的字典映射IDictionary<Type, Expression>
,并在Get
方法中查找typeof(T)
,但我不确定在本例中是否能够强键入表达式。
如何根据Get
T
__的类型将“默认”LINQ表达式注入到__方法中?我希望有一种可扩展的、面向对象的方法将类型映射到默认表达式。
发布于 2013-09-26 06:05:05
因为每个IPersisted
类型都有自己的表达式,所以我会将其作为IPersisted
的一个约束。所以现在你有了某种多态。
有点像?
interface IPersisted<T> where T: IPersisted<T>
{
Expression<Func<T, bool>> Predicate { get; }
}
class Repo<T> where T : IPersisted<T>, new()
{
public IQueryable<T> Get()
{
var dummy = new T();
return _queryable.Where(dummy.Predicate);
}
}
class Deletable : IPersisted<Deletable>
{
public Deletable()
{
}
public Expression<Func<Deletable, bool>> Predicate
{
get { return x => !x.IsDeleted; }
}
bool IsDeleted { get; set; }
}
我认为这里需要的是某种静态多态,but since C# doesnt offer that,您可能需要为自己创建一个虚拟实例,以获得表达式。
如果不能使用默认构造函数,则可以依赖FormatterServices.GetUninitializedObject(t)
。您可以像这样调整Get
方法:
public IQueryable<T> Get()
{
var dummy = (T)FormatterServices.GetUninitializedObject(typeof(T));
return _queryable.Where(dummy.Predicate);
}
关于FormatterServices.GetUninitializedObject
可能需要注意的许多事情中的两件事
如果确切的表达式不重要,那么您可以去掉对象实例化。类似于:
interface IPersisted<T> where T: IPersisted<T>
{
Func<T, bool> Predicate { get; }
}
class Repo<T> where T : IPersisted<T>
{
public IQueryable<T> Get()
{
return _queryable.Where(x => x.Predicate(x));
}
}
class Deletable : IPersisted<Deletable>
{
public Func<Deletable, bool> Predicate
{
get { return x => !x.IsDeleted; }
}
}
如果保留IPersisted
的原始定义很重要,那么您可以将其非泛型化。不确定这是否会使它的类型更少。
interface IPersisted
{
Expression<Func<object, bool>> Predicate { get; }
}
class Repo<T> where T : IPersisted
{
public IQueryable<T> Get()
{
return _queryable.Where(dummy.Predicate);
}
}
class Deletable : IPersisted
{
public Expression<Func<object, bool>> Predicate
{
get { return x => !((Deletable)x).IsDeleted; }
}
}
通过在IPersisted
中使用一个方法,可以使上述方法具有更强的类型,但不一定需要足够好的约束:
interface IPersisted
{
Expression<Func<T, bool>> GetPredicate<T>() where T : IPersisted;
}
class Repo<T> where T : IPersisted
{
public IQueryable<T> Get()
{
return _queryable.Where(dummy.GetPredicate<T>());
}
}
class Deletable : IPersisted
{
Expression<Func<T, bool>> IPersisted.GetPredicate<T>() //made it explicit
{
return x => ((Deletable)(object)x).IsDeleted;
}
}
注意:如果Predicate
实现在Repo<T>
类之外没有意义,则将其显式化。
发布于 2013-09-26 05:37:50
不确定我们是否100%在同一个页面上,但是这个get方法示例将采用linq,您可以使用它作为where子句来过滤查询。
class Repo<T> where T : IPersisted
{
IQueryable<T> Get(Func<T, bool> filter)
{
return _queryable.Where(filter);
}
}
编辑:不确定这是否能很好地转化为sql,但为了确保我对你想要的东西有正确的想法(也许还会引发一丝希望):你考虑过这样的事情吗?
class Repo<T> where T : IPersisted
{
IQueryable<T> Get()
{
if (typeof (T).IsAssignableFrom(typeof (IDeletable)))
{
return _queryable.Where(o => ((IDeletable) o).Deleted = false).AsQueryable();
}
return _queryable;
}
}
https://stackoverflow.com/questions/19029510
复制