Warning: file_get_contents(/data/phpspider/zhask/data//catemap/8/linq/3.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
C# 具有泛型类属性的LINQ表达式_C#_Linq_Generics_Lambda - Fatal编程技术网

C# 具有泛型类属性的LINQ表达式

C# 具有泛型类属性的LINQ表达式,c#,linq,generics,lambda,C#,Linq,Generics,Lambda,我想将一个IQueryable和一个ID数组传递给一个基于这些ID过滤IQueryable的方法 由于ID可以是long或int,因此应该一般地解决它 我得出了以下结论: public static IEnumerable<T> GetModified<TId, T>(IQueryable<T> objects, TId[] ids) where T : class { return objects.Where(j => ids.Cont

我想将一个IQueryable和一个ID数组传递给一个基于这些ID过滤IQueryable的方法

由于ID可以是long或int,因此应该一般地解决它

我得出了以下结论:

public static IEnumerable<T> GetModified<TId, T>(IQueryable<T> objects, TId[] ids) where T : class
{
        return objects.Where(j => ids.Contains((TId)j.GetType().GetProperty("Id").GetValue(j)));
}
公共静态IEnumerable GetModified(IQueryable对象,TId[]id),其中T:class
{
返回objects.Where(j=>ids.Contains((TId)j.GetType().GetProperty(“Id”).GetValue(j));
}
不幸的是,我得到了一个例外:

LINQ to Entities无法识别方法“System.Object GetValue(System.Object)”方法,并且无法将此方法转换为存储表达式


实体框架不支持某些.NET方法,例如
GetValue()
,因为它不转换为SQL(这是实际执行到
IQueryable
的代码)。在执行反射之前,请尝试调用
ToList
以获取CLR对象:

public static IEnumerable<T> GetModified<TId, T>(IQueryable<T> objects, TId[] ids) where T : class
{
    return objects.ToList().Where(j => ids.Contains((TId)j.GetType().GetProperty("Id").GetValue(j)));
}
公共静态IEnumerable GetModified(IQueryable对象,TId[]id),其中T:class
{
返回objects.ToList(),其中(j=>ids.Contains((TId)j.GetType().GetProperty(“Id”).GetValue(j));
}

异常是正常的,因为通过反射获取属性显然无法转换为SQL

我要尝试的一件事是创建一个通用接口,该接口公开给定类型的
Id
属性:

public interface HasId<T> {
    T Id { get; set; }
}
注意添加的通用限制:
其中T:class,HasId
。这使您能够编写简化的
j.Id
,它返回一个
TId
值,而不是诉诸反射

请注意,我没有运行或测试这段代码;这只是我在看到您的问题时得到的一个想法,我希望它能有所帮助

更新: 下面是另一个可能的解决方案,它不需要您以任何方式声明接口或更改类:

public static IEnumerable<T> GetModified<TId, T>
    (IQueryable<T> objects, TId[] ids, Expression<Func<T, TId>> idSelector) 
    where T : class
{
    return objects.Where(j => ids.Contains(idSelector(j)));
}
(只有第三个参数是新的;保持其他参数不变)


再说一次,我还没有测试它是否有效,甚至没有编译,因为我这里没有一台装有VS的计算机:(.

这是可行的,但效率非常低,因为所有对象都是从数据库中提取的,对吗?这是正确的。但由于您需要反射,LINQ-to-Entite无法将反射代码转换为SQL。我想您可以尝试
objects.Cast()。其中(a=>ids.Contains(a.Id))
亲爱的先生,这是一个很好的答案!我没有尝试第二种方法,但第一种方法很有效。第二种方法没有达到预期效果。错误:“idSelector”是一个变量,但用作方法。我问了另一个与第二种方法相关的问题。如果您感兴趣,请参阅
public static IEnumerable<T> GetModified<TId, T>
    (IQueryable<T> objects, TId[] ids, Expression<Func<T, TId>> idSelector) 
    where T : class
{
    return objects.Where(j => ids.Contains(idSelector(j)));
}
var modified = GetModified(dbObjects, yourIdArray, entity => entity.Id);