如何在泛型类中映射默认的LINQ表达式 [英] How to map a default LINQ expression in a generic class
问题描述
我有一个通用的 Repo
类暴露数据库LINQ提供者:
class Repo< T>其中T:IPersisted
{
IQueryable< T> Get()
{
return _queryable;
}
}
( IPersisted
是一个用于持久化对象的简单标记界面。)
现在...我想找到一种优雅的方法来为某些派生的注入一个默认的LINQ表达式IPersisted的类型
。例如,对于以下IPersisted实现:
class Deletable:IPersisted
方法返回
{
bool IsDeleted {get ;组; $ $ $ $ $ $ $ $ $ $ $ $ $ $ $ $ $ $ $ $ $ $ $ $ $ $ $ $ $ $ $ $
$ bGet()
_queryable.Where(q =>!q.IsDeleted)
,只有当T
类型为可删除
。
我想到了创建一些类型的字典映射
IDictionary< Type,Expression>
,并在Get
中查找 typeof(T)
/ code>方法,但我不知道我可以在这种情况下强烈键入表达式。
我如何注入根据
T
的类型,将Get
方法中的默认LINQ表达式 d喜欢有一个可扩展的,面向对象的方式将类型映射到默认表达式。解决方案由于每个
IPersisted
类型将有自己的表达式,我会使这个限制在IPersisted
部分。所以现在你有某种多态性。
有什么东西?
接口IPersisted< T>其中T:IPersisted< T>
{
表达式< Func< T,bool>>>谓词{get; }
}
class Repo< T>其中T:IPersisted< T>,new()
{
public IQueryable< T> Get()
{
var dummy = new T();
return _queryable.Where(dummy.Predicate);
}
}
class可删除:IPersisted<可删除>
{
public Deletable()
{
}
public Expression< Func< Deletable,bool>>谓词
{
get {return x => !x.IsDeleted; }
}
bool IsDeleted {get;组; }
}
我想你这里需要的是某种静态多态,但是由于C#不提供,您可能需要为自己创建一个虚拟实例,只是为了获取表达式。
如果你不能有默认的构造函数,那么你可以依靠
FormatterServices.GetUninitializedObject (t)的
。您可以调整Get
方法,如下所示:public IQueryable&T ; Get()
{
var dummy =(T)FormatterServices.GetUninitializedObject(typeof(T));
return _queryable.Where(dummy.Predicate);
}
可能有许多关于
FormatterServices.GetUninitializedObject
:
它不会初始化任何东西或运行构造函数,但这不应该是我们的问题。
相对较慢。不应该是一个很大的事情,因为你可以缓存实例:)一些东西:
class Repo< T>其中T:IPersisted< T>
{
//缓存机制:每个实例只运行一次;你可以使它
//静态如果这个shud只运行一次应用程序的整个生命周期
readonly T dummy =(T)FormatterServices.GetUninitializedObject(typeof(T));
public IQueryable< T> Get()
{
return _queryable.Where(dummy.Predicate);
}
}
如果确切的表达式不重要,那么可以摆脱对象实例化。类似于:
界面IPersisted< T>其中T:IPersisted< T>
{
Func< T,bool>谓词{get; }
}
class Repo< T>其中T:IPersisted< T>
{
public IQueryable< T> Get()
{
return _queryable.Where(x => x.Predicate(x));
}
}
class可删除:IPersisted<可删除>
{
public Func< Deletable,bool>谓词
{
get {return x => !x.IsDeleted; }
}
}
如果保留
IPersisted
的原始定义很重要,那么可以使其非泛型。不确定是否会使它不那么强烈类型。界面IPersisted
{
表达式< Func< object,bool>>>谓词{get; }
}
class Repo< T>其中T:IPersisted
{
public IQueryable< T> Get()
{
return _queryable.Where(dummy.Predicate);
}
}
class可删除:IPersisted
{
public Expression< Func< object,bool>>谓词
{
get {return x => !((可删除)x)的.IsDeleted; }
}
}
上述方法可以通过在
IPersisted
中的方法进行更强烈的类型化,但不需要足够的限制:interface IPersisted
{
表达式< Func< T,bool>> GetPredicate< T>()其中T:IPersisted;
}
class Repo< T>其中T:IPersisted
{
public IQueryable< T> Get()
{
return _queryable.Where(dummy.GetPredicate< T>());
}
}
class可删除:IPersisted
{
表达式< Func< T,bool>> IPersisted.GetPredicate< T>()//使其显式
{
return x => ((可删除)(对象)x)的.IsDeleted;
}
}
注意:如果在
Repo< T>
类之外没有意义,请使Predicate
实现。 p>I have a generic
Repo
class that exposes a database LINQ provider:class Repo<T> where T : IPersisted { IQueryable<T> Get() { return _queryable; } }
(
IPersisted
is a simple marker interface for persisted objects).Now... I would like to find an elegant way to inject a default LINQ expression for certain derived types of
IPersisted
. For example, for the following IPersisted implementation:class Deletable : IPersisted { bool IsDeleted { get; set; } }
I want the
IQueryable<T> Get()
method to return_queryable.Where(q => !q.IsDeleted)
, only whenT
is of typeDeletable
.I thought about creating some type of dictionary map
IDictionary<Type, Expression>
, and doing a lookup ontypeof(T)
inside theGet
method but I'm not sure that I'll be able to strongly type the expressions in this case.How can I inject a "default" LINQ expression into the
Get
method, based on the type ofT
? I'd like to have an extensible, object oriented way of mapping types to default expressions.解决方案Since each
IPersisted
type is going to have its own expression, I would make that a constraint on the part ofIPersisted
. So now you have some kind of polymorphism.Something like?
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; } }
I think what you need here is some kind of static polymorphism, but since C# doesnt offer that, you might need create a dummy instance for yourself, just to get the expression.
If you can't have a default constructor, then you can rely on
FormatterServices.GetUninitializedObject(t)
. You can adjust yourGet
method like this:public IQueryable<T> Get() { var dummy = (T)FormatterServices.GetUninitializedObject(typeof(T)); return _queryable.Where(dummy.Predicate); }
Two things out of possibly many things to note about
FormatterServices.GetUninitializedObject
:
It will not initialize anything or run the constructor, but that shouldn't be a problem for us.
It's relatively slower. Shouldn't be a big deal since you can cache the instances :) Something like:
class Repo<T> where T : IPersisted<T> { //caching mechanism: this is run only once per instance; you can make it //static if this shud be run only once the entire lifetime of application readonly T dummy = (T)FormatterServices.GetUninitializedObject(typeof(T)); public IQueryable<T> Get() { return _queryable.Where(dummy.Predicate); } }
If the exact expression is not important, then you can get rid of the object instantiation. Something like:
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; } } }
If preserving the original definition of
IPersisted
is important, then you can make it non-generic. Not sure if that would make it any less strongly-typed.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; } } }
The above approach can be made more strongly typed by going for a method in
IPersisted
but need not be good enough a constraint: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; } }
Note: Make the
Predicate
implementation explicit if it doesn't make sense outside theRepo<T>
class.这篇关于如何在泛型类中映射默认的LINQ表达式的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!