您好我是C#的新手,并从互联网上找到了这段代码:
public class InMemoryObjectSet<T>
: IObjectSet<T> where T : class
{
readonly HashSet<T> _set;
readonly IQueryable<T> _queryableSet;
public InMemoryObjectSet(IEnumerable<T> entities)
{
_set = new HashSet<T>();
foreach (var entity in entities)
{
_set.Add(entity);
}
_queryableSet = _set.AsQueryable();
}
public Expression Expression
{
get { return _queryableSet.Expression; }
}
public IQueryProvider Provider
{
get { return _queryableSet.Provider; }
}
public IEnumerator<T> GetEnumerator()
{
return _set.GetEnumerator();
}
IEnumerator IEnumerable.GetEnumerator()
{
return GetEnumerator();
}
/* Ignore Add, Delete operations */
}
我试图在InMemoryObjectSet中找到一个元素,条件名是&#39; xx&#39;。当然我可以使用IEnumerator循环但我只是想知道是否可以使用linq-ish方式:
var inMemoryItems = new InMemoryObjectSet<Customer>();
System.Linq.Expressions.Expression<Customer> exp = (x => x.Name == "xx");
var findItem = inMemoryItems.Provider.CreateQuery<Customer>(exp);
错误是:
Cannot convert lambda expression to type 'Customer' because it is not a delegate type
有人可以帮忙吗?
答案 0 :(得分:1)
您想创建一个Expression
,可用于过滤您的Customers
集合。
您的错误是表达式的签名不正确。
我花了一段时间才看到你InMemoryObjectSet<T>
的目的。 HashSet already implements
IEnumerable`,因此可以处理你想要的所有LINQ语句。
但显然你想要一个实现IQueryable<T>
的类,所以你可以处理你的InMemorySet对象AsQueryable
如果要从IQueryable中过滤出TSource类型的某些元素,则需要以下类型的表达式:
Expression<Func<TSource, bool>> expr = ...
在您创建表达式后,您可以将IObjectSet<TSource>
过滤为仅包含与您的表达式匹配的元素的IQueryable<TSource>
。
IObjectSet<TSource>
实现IQueryable<TSource>. An
IQueryable`隐藏了您要查询的集合所在的位置,以及如何访问集合中的元素。
该集合可以位于数据库,文件,Internet或InMemoryObjectSet中。
由于隐藏了这些信息,您不必知道查询所在的项目集合以及访问方式(SQL?其他方法?)
每个IQueryable
都包含Expression
和Provider
。 Expression
通常由您使用LINQ语句填充。这是&#39;提供商的任务。将Expression
转换为基础集合理解的格式并将其发送到此基础集合。
对于数据库,Provider
会将Expression
转换为SQL,对于InMemorySet
,转换将更简单,它将转换IEnumerable中的表达式以访问基础HashSet。
看到这一点,您不应该访问Provider
。您应该只创建Expression
并使用ToList()
,First()
,Any()
,Count()
等执行方法来执行Expression
并获取结果
回到你的问题。正确使用将是: (在婴儿步骤中,所以你可以看到所有潜在的类型)
InMemorySet<Customer> customerCollection = new InMemorySet<Customer>();
IQueryable<Customer> customers = customerCollection;
从这里,您不再了解您的客户是否在数据库中
一个文件,InMemorySet
或其他什么。
由于此信息隐藏,以下代码适用于任何这些集合
使用正确的LINQ获取名称为XX的所有客户:
IQueryable<Cusomter> xxCustomers = customers.Where(customer => customer.Name == XX);
使用ToList()
或类似内容执行查询
或者:创建一个Expression
并在过滤函数中使用它:
string XX = ...
Expression<Func<Customer, bool>> expr = customer => customer.Name == XX;
IQueryable<Customer> result1 = customers.Where(expr);
ToList()
将命令result1的Provider执行表达式。
真正低级别的方法是告诉提供商访问
// (2) Use the Provider
IQueryProvider provider = customers.Provider;
object query2 = provider.Execute(customers.Expression)
但是再一次:不要这样做,你将丢失隐藏的信息,导致你的代码不再适用于任何IQueryable