如何检查扩展方法中的“类型”中是否存在属性

本文关键字:类型 是否 属性 存在 方法 何检查 检查 扩展 | 更新日期: 2023-09-27 18:15:13

我经常有这样的代码:

var stRecs = db.<someTable>
             .Where(a => a.DepID == depID)

选择一条记录,但是如果depID == 0我想要返回所有记录。

我正在考虑创建一个扩展方法"WhereDepID_OrAll",如

public static IQueryable<T> WhereDepID_OrAll<T>(this IQueryable<T> source)
        where T: // is what?
{
    if(depID > 0) { return source.Where(a => a.depID == depID); }
    else return source.Where(a => a);
}
现在我的基本问题是:我有几个表与depID -我如何设置Where T: ?
该方法如何确定表是否有depID?

解决潜在问题的更好方法?

如何检查扩展方法中的“类型”中是否存在属性

乍一看,反应是:创建一个接口

public interface ObjectWithDepartmentInterface {
    int depID;
}

使所有使用此depId的实体实现此接口,并使用

where T : ObjectWithDepartmentInterface

但是linq to entities不接受query…基于接口

生成的表达式

所以唯一的方法是让你的实体从一个具有depId属性的公共实体(可能是抽象实体)继承一个depId。

并使用这个抽象实体作为

where T:

一种更简单(但更难看)的方法是不给T添加约束,在方法中构建谓词,在糟糕的情况下抛出异常。

if (typeof(T).GetProperty("depId") == null)
   throw InvalidOperationException (string.Format("{0}" doesn't have a depId property, typeof(T).Name))

编辑

但也许这不是depId作为共同属性的问题

public static IQueryable<T> WhereExistsOrAll<T>(this IQueryable<T> source, string propertyName, int value)
        where T: // is what?
{
    if (value == 0)
    return source;
    var parameter = Expression.Parameter(typeof(T), "m");
    Expression member = parameter;
    member = Expression.Property(member, propertyName);
    member = Expression.Equals(member, Expression.Constant(value));
    var lambda = Expression.Lambda<Func<T, bool>>(member, new[]{parameter});
    return source.Where(lambda);
}
使用

var stRecs = db.<someTable>.WhereExistsOrAll("depId", depId);

编辑2

另一种方法是解析谓词以获得"常量"值

之类的

public static IQueryable<T> GetAllOrRestrict<T>(this IQueryable<T> queryable, Expression<Func<T, bool>> predicate)
{
       var expression = predicate.Body as BinaryExpression;
       var rightPart = expression.Right as MemberExpression;
       var value = GetValue(rightPart);
       var test = value.ToString();
       int val;
       if (Int32.TryParse(value.ToString(), out val))
       {
           if (val != 0)
               return queryable.Where(predicate);
       }
       return queryable;
}
private static object GetValue(MemberExpression member)
{
     var objectMember = Expression.Convert(member, typeof(object));
     var getterLambda = Expression.Lambda<Func<object>>(objectMember);
     var getter = getterLambda.Compile();
     return getter();
}
使用

var stRecs = db.<someTable>.GetAllOrRestrict(m => m.depID == depId);

我知道这不是特别时尚,但这不正是实体框架中的查询生成器方法吗?

var stRecs = db.<someTable>
             .Where("it.DepID == @depID OR @depID = 0", 
                    new ObjectParameter("depID", depID));

这适用于任何someTable,这样它就有一个名为DepID的列。它当然可以是一个扩展方法:

public static ObjectQuery<T> WhereIdEqualOrAll<T>(this ObjectQuery<T> q, int depID)
    where T : class
{
    return q.Where("it.DepID = @id OR @id = 0", new ObjectParameter("id", id));
}

可以这样调用:

var stRecs = db.<someTable>.WhereIdEqualOrAll(depID);

使用接口:

public interface IInterface
{
   int depId;
}

这将强制T继承IInterface并实现depId

然后你可以把它添加到扩展名:

public static IQueryable<T> WhereDepID_OrAll<T>(this IQueryable<T> source) where T: IInterface
{
}

使用一个接口,然后手动构建一个表达式树,引用实际的类。

Raphaels Edit 2做到了!

小版:如果存在DepID,我如何包含null值?

我喜欢返回ID == x或ID == NULL的所有部门

可能与一个额外的bool包括ullvalues)

public static IQueryable<T> GetAllOrRestrict<T>(this IQueryable<T> queryable,
 Expression<Func<T, bool>> predicate, 
 bool includeNullValues)
    {
        var expression = predicate.Body as BinaryExpression;
        var rightPart = expression.Right as MemberExpression;
        var value = GetValue(rightPart);
        var test = value.ToString();
        int val;
        if (Int32.TryParse(value.ToString(), out val))
        {
            if (val != 0)
            {
                if (includeNullValues)
                {
                    var parameter = Expression.Parameter(typeof(T),"m");
                    return queryable.Where(predicate) <====HOW to " || depID == null) ???
                }
                else
                {
                return queryable.Where(predicate);
                }
            }
        }
        return queryable;
    }