如何在泛型类中映射默认的LINQ表达式 [英] How to map a default LINQ expression in a generic class

查看:117
本文介绍了如何在泛型类中映射默认的LINQ表达式的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我有一个通用的 Repo 类暴露数据库LINQ提供者:

  class Repo< T>其中T:IPersisted 
{
IQueryable< T> Get()
{
return _queryable;
}
}

IPersisted 是一个用于持久化对象的简单标记界面。)



现在...我想找到一种优雅的方法来为某些派生的注入一个默认的LINQ表达式IPersisted的类型 。例如,对于以下IPersisted实现:

  class Deletable:IPersisted 
{
bool IsDeleted {get ;组; $ $ $ $ $ $ $ $ $ $ $ $ $ $ $ $ $ $ $ $ $ $ $ $ $ $ $ $ $ $ $ $




$ b

Get()方法返回 _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


  1. 它不会初始化任何东西或运行构造函数,但这不应该是我们的问题。


  2. 相对较慢。不应该是一个很大的事情,因为你可以缓存实例:)一些东西:

      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 when T is of type Deletable.

I thought about creating some type of dictionary map IDictionary<Type, Expression>, and doing a lookup on typeof(T) inside the Get 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 of T? 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 of IPersisted. 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 your Get 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:

  1. It will not initialize anything or run the constructor, but that shouldn't be a problem for us.

  2. 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 the Repo<T> class.

这篇关于如何在泛型类中映射默认的LINQ表达式的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆