C# 强制转换泛型类型以生成有效的Linq表达式

C# 强制转换泛型类型以生成有效的Linq表达式,c#,linq,generics,casting,C#,Linq,Generics,Casting,我一直在尝试泛型转换或构建可以转换为所需泛型类型的LINQ表达式T 下面是一个失败的例子: public override void PreprocessFilters<T>(ISpecification<T> specification) { if (typeof(ICompanyLimitedEntity).IsAssignableFrom(typeof(T))) { var companyId = 101; // not releva

我一直在尝试泛型转换或构建可以转换为所需泛型类型的LINQ表达式
T

下面是一个失败的例子:

public override void PreprocessFilters<T>(ISpecification<T> specification)
{
    if (typeof(ICompanyLimitedEntity).IsAssignableFrom(typeof(T)))
    {
        var companyId = 101; // not relevant, retrieving company ID here

        // and now I need to call the method AddCriteria on the specification
        // as it were ISpecification<ICompanyLimitedEntity>
        // which it should be because at this point I know 
        // that T is ICompanyLimitedEntity
        var cle = specification as ISpecification<ICompanyLimitedEntity>;
        //                      ^-- but of course this conversion won't work, cle is null

        // what should I do now?

        // I need to call it like this:
        cle.AddCriteria(e => e.CompanyId == null ||
            e.CompanyId == 0 || e.CompanyId == companyId);
        // BTW, AddCriteria receives Expression<Func<T, bool>> as an argument

        // tried nasty casts inside of the expression - this doesn't throw NullReference
        // but it doesn't translate to SQL either - gets evaluated locally in memory, which is bad
        specification.AddCriteria(e => ((ICompanyLimitedEntity)e).CompanyId == null ||
            ((ICompanyLimitedEntity)e).CompanyId == 0 || 
            ((ICompanyLimitedEntity)e).CompanyId == companyId);

        // this one also doesn't work

        Expression<Func<ICompanyLimitedEntity, bool>> lex = e => e.CompanyId == null ||
                    e.CompanyId == 0 || e.CompanyId == companyId;

        // it's null again -----------v
        specification.AndCriteria(lex as Expression<Func<T, bool>>);
    }
}
公共覆盖无效预处理过滤器(ISpecification规范)
{
if(typeof(ICompanyLimitedEntity).IsAssignableFrom(typeof(T)))
{
var companyId=101;//不相关,在此处检索公司ID
//现在我需要调用规范中的AddCriteria方法
//因为它是一种特殊的
//这应该是因为在这一点上我知道
//那是我公司的有限财产
var-cle=作为规范的规范;
//^--但是这个转换当然不起作用,cle是空的
//我现在该怎么办?
//我需要这样称呼它:
cle.AddCriteria(e=>e.CompanyId==null||
e、 公司ID==0 | | e.CompanyId==CompanyId);
//顺便说一句,AddCriteria接收表达式作为参数
//尝试了表达式内部的强制类型转换-这不会抛出NullReference
//但它也不能转换成SQL,而是在内存中本地计算,这是不好的
specification.AddCriteria(e=>((ICompanyLimitedEntity)e).CompanyId==null||
((ICompanyLimitedEntity)e).CompanyId==0 | |
((ICompanyLimitedEntity)e).CompanyId==CompanyId);
//这个也不行
表达式lex=e=>e.CompanyId==null||
e、 CompanyId==0 | | e.CompanyId==CompanyId;
//它又是空的------v
规范和标准(lex作为表达式);
}
}

是否有方法强制转换T或构建Linq表达式,将
T
视为
ICompanyLimitedEntity
,并在SQL server上执行查询?

以下是构建所需表达式的方法

首先,使用接口类型参数创建编译时表达式

Expression<Func<ICompanyLimitedEntity, bool>> exprI = e => e.CompanyId == null ||
            e.CompanyId == 0 || e.CompanyId == companyId;
其中,
ReplaceParameter
是典型的基于
ExpressionVisitor
的帮助程序,用于将参数替换为另一个表达式:

var parameterT = Expression.Parameter(typeof(T), "e");
var bodyT = exprI.Body.ReplaceParameter(exprI.Parameters[0], parameterT);
var exprT = Expression.Lambda<Func<T, bool>>(bodyT, parameterT);
public static partial class ExpressionUtils
{
    public static Expression ReplaceParameter(this Expression expression, ParameterExpression source, Expression target)
        => new ParameterReplacer { Source = source, Target = target }.Visit(expression);

    class ParameterReplacer : ExpressionVisitor
    {
        public ParameterExpression Source;
        public Expression Target;
        protected override Expression VisitParameter(ParameterExpression node)
            => node == Source ? Target : node;
    }
}

请注意,您仍然需要来自

的成员访问表达式修复程序。您是否尝试过
公共覆盖无效预处理过滤器(ISpecification规范),其中T:ICompanyLimitedEntity
?这也使得<代码>是可从<代码>检查冗余的。@Funk如果T始终是ICompanyLimitedEntity,这将是最好的解决方案,但它不能保证是。