gpt4 book ai didi

c# - 如何在泛型类中映射默认 LINQ 表达式

转载 作者:行者123 更新时间:2023-11-30 16:15:55 25 4
gpt4 key购买 nike

我有一个通用的 Repo公开数据库 LINQ 提供程序的类:

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

(IPersisted 是持久对象的简单标记接口(interface))。

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

class Deletable : IPersisted
{
bool IsDeleted { get; set; }
}

我想要 IQueryable<T> Get()返回方法 _queryable.Where(q => !q.IsDeleted) , 只有当 T类型为 Deletable .

我考虑创建某种类型的字典映射 IDictionary<Type, Expression> ,并查找 typeof(T)Get里面方法,但我不确定在这种情况下我是否能够强类型化表达式。

如何将“默认”LINQ 表达式注入(inject) Get方法,基于 T 的类型? 我想要一种可扩展的、面向对象的方式来将类型映射到默认表达式。

最佳答案

因为每个IPersisted type 将有自己的表达式,我会把它作为 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 的可能很多事情中有两件事需要注意:

  1. It will not initialize anything or run the constructor ,但这对我们来说应该不是问题。

  2. It's relatively slower .应该没什么大不了的,因为您可以缓存实例 :) 类似的东西:

    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);
    }
    }

如果确切的表达式不重要,那么你可以摆脱对象实例化。像这样的东西:

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> 之外没有意义,则显式实现类。

关于c# - 如何在泛型类中映射默认 LINQ 表达式,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/19029510/

25 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com