2017-10-20 25 views
1

您好我是新来的C#,发现这个代码从互联网:如何有条件地选择具有可查询linq的哈希集中的项目?

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与条件名称的元素是“XX”。当然,我可以使用的IEnumerator遍历,但我只是想知道是否可以使用LINQ上下的方式:

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

为什么不只是'_queryableSet.Whre(x => x.Name ==“xx”)''? –

+0

没有特别的原因,只是一个条件样本。 – LOUDKING

回答

1

您想创建一个Expression,可用于过滤您的Customers集合。

您的错误是您的表情签名不正确。

我花了一段时间才看到您的InMemoryObjectSet<T>的目的。 HashSet already implements IEnumerable`,因此可能已经处理了所有你想要的LINQ语句。

但很显然,你想实现IQueryable<T>一类,所以如果你想从一个IQueryable你需要以下类型的表达式过滤掉类型TSource的某些元素,你可以处理你的InMemorySet对象AsQueryable

Expression<Func<TSource, bool>> expr = ... 

一旦你创建你的表情,你可以过滤IObjectSet<TSource>仅包含符合您的表达式中的元素进行IQueryable<TSource>

IObjectSet<TSource> implements IQueryable<TSource>. An IQueryable`隐藏您要查询的集合的位置以及集合中元素的访问方式。

集合可以位于数据库,文件,互联网或InMemoryObjectSet中。

因为这个信息隐藏的,你真的没有知道你的项目的集合查询所在,以及如何访问(SQL?其他的方法?)

每个IQueryable包含Expression和一个ProviderExpression通常由您使用LINQ语句填充。 “提供者”的任务是将Expression转换为底层集合理解的格式并将其发送到此底层集合。

对于数据库的Provider将翻译Expression到SQL,对于InMemorySet翻译会更简单,它会在一个IEnumerable翻译表达访问底层HashSet的。

看到这个,你不应该访问Provider。您只应创建Expression并使用execution子手方法(如ToList(),First(),Any(),Count())执行Expression并获得结果。

回到你的问题。正确的用法是: (在婴儿的步骤,所以你可以看到所有的基础类型)

InMemorySet<Customer> customerCollection = new InMemorySet<Customer>(); 
IQueryable<Customer> customers = customerCollection; 

从这里,你不知道了你的客户是否在数据库 一个文件,InMemorySet,或任何。 因为这些信息隐藏在下面的代码可以在任何这些集合

获取所有客户的名字XX,使用正确的LINQ:

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执行表达式。

一个非常低的水平的方法是告诉提供商访问

// (2) Use the Provider 
IQueryProvider provider = customers.Provider; 
object query2 = provider.Execute(customers.Expression) 

但再次声明:不这样做,你就失去了信息隐藏,导致它不再保证你的代码适用于任何IQueryable

相关问题