C#中的Where的使用

一、约束

约束类型包括基类约束、构造函数约束、接口约束、参数约束等。如:

public class FateherTest
{
}
//where的用法 接口约束IComparable 和构造函数约束new(), 基类约束 FatherTest
public class TestA<T> where T : FateherTest, IComparable, new()
{
}

public class TestB
{
 //限制传递参数的类型必须继承IComparable 参数类型约束
    public int Caculate<T>(T t) where T : IComparable
    {
        throw new NotImplementedException();
    }
}

二、集合条件查询

1.使用方法

  List<InstanceB> list = new List<InstanceB>();
  //返回b.value的值 ==2的 IEnumerable对象
  list.Where((b) => b.value == 2).ToList();
  Dictionary<int, InstanceB> dic = new Dictionary<int, InstanceB>();
  //TSource是 KeyValuePair<TKey, TValue>
  dic.Where((b) => b.Value.value== 2);

2.如何实现的

在System.linq命名空间下的Enumerable类里面实现了IEnumerable的扩展方法.如下:

 //返回值是IEnumerable<T>迭代器对象

 public static IEnumerable<TSource> Where<TSource>(
      this IEnumerable<TSource> source,
      Func<TSource, bool> predicate)
    {
      if (source == null)
        throw Error.ArgumentNull(nameof (source));
      if (predicate == null)
        throw Error.ArgumentNull(nameof (predicate));
      switch (source)
      {
        case Enumerable.Iterator<TSource> _:
          return ((Enumerable.Iterator<TSource>) source).Where(predicate);
        case TSource[] _:
          return (IEnumerable<TSource>) new Enumerable.WhereArrayIterator<TSource>((TSource[]) source, predicate);
        case List<TSource> _:
          return (IEnumerable<TSource>) new Enumerable.WhereListIterator<TSource>((List<TSource>) source, predicate);
        default:
          return (IEnumerable<TSource>) new Enumerable.WhereEnumerableIterator<TSource>(source, predicate);
      }
    }

 当我们调用List.Where扩展方法时返回了一个WhereListIterator对象:

reurn  (IEnumerable<TSource>) new Enumerable.WhereListIterator<TSource>((TSource[]) source, predicate) 返回一个whereListIterator对象。其中 TSource就是InstanceB类型

我们可查看 WhereListIterator 这个类,它继承了:Enumerable.Iterator<TResult>:IEnumerable<TSource> .其本身实现了迭代器的功能,查看MoveNext方法:

      public override bool MoveNext()
      {
        if (this.state == 1)
        {
          while (this.index < this.source.Length)
          {
            TSource source = this.source[this.index];
            ++this.index;
            if (this.predicate(source))
            {
              this.current = source;
              return true;
            }
          }
          this.Dispose();
        }
        return false;
      }

    只有通过predictate的检测之后MoveNext才会返回true.调用Tolist的时候回调用 IEnumrable的扩展方法Tolist 调用创建一个List<T>对象返回。只不过构造函数是使用集合做的初始化,如下:

    [__DynamicallyInvokable]

    public List(IEnumerable<T> collection)
    {
      if (collection == null)
        ThrowHelper.ThrowArgumentNullException(ExceptionArgument.collection);

      if (collection is ICollection<T> objs)
      {
        int count = objs.Count;
        if (count == 0)
        {
          this._items = List<T>._emptyArray;
        }
        else
        {
          this._items = new T[count];
          objs.CopyTo(this._items, 0);
          this._size = count;
        }
      }
      else
      {
        this._size = 0;
        this._items = List<T>._emptyArray;
        foreach (T obj in collection)
          this.Add(obj);
      }
    }

上面使用foreach会调用WhereListIterator 的MoveNext.直到返回false结束。而上面的MoveNext用来Func委托函数做筛选。

我们还可以做如下操作:

var  whereListIt  = list.Where((b) => b.value >1) 
 Func<InstanceB,InstanceB> func = delegate (InstanceB b)
 {
     b.value = 3;
     return b;
  };
newList = whereListIt.Select(func).ToList();

筛选出第一次b.value >1的独享 第二次将筛选对象的value都设置为3.

      public override bool MoveNext()
      {
        if (this.state == 1)
        {
          while (this.index < this.source.Length)
          {
            TSource source = this.source[this.index];
            ++this.index;
            if (this.predicate == null || this.predicate(source))
            {
//这里可以看出Selector是对source进行操作,并不是筛选。
              this.current = this.selector(source);
              return true;
            }
          }
          this.Dispose();
        }
        return false;
      }

几个类结构如下:

  1. WhereListIterator:Enumerable.Iterator<TResult>:IEnumerable<TSource>
  2. WhereListIterator:Enumerable.Iterator<TResult>:IEnumerable<TSource>

  所以有连续的操作如:

list.Where((b) => b.value == 2).where((b) => b.value == 2)
Func<InstanceB,InstanceB> func = delegate (InstanceB b)
        {
            b.value = 3;
            return b;
        };
list.Select(t).Select(t)

也可以有组合的操作

list.Where((b) => b.value == 2).Select(t)

原因是连续操作内部做了 Combine操作:下面是Selector调用Selector即:Selector.Selector
public override IEnumerable<TResult2> Select<TResult2>(
        Func<TResult, TResult2> selector) {
        return (IEnumerable<TResult2>) new Enumerable.SelectEnumerableIterator<TSource, TResult2>(this._source, Enumerable.CombineSelectors<TSource, TResult, TResult2>(this._selector, selector));
}
组合操作做了组合:下面是Selector.Where的组合操作
public override IEnumerable<TResult> Where(Func<TResult, bool> predicate) => (IEnumerable<TResult>) new Enumerable.WhereEnumerableIterator<TResult>((IEnumerable<TResult>) this, predicate);

/组合操作时会把This当前对象传递到下个对象WhereEnumerableIterator。WhereEnumerableIterator在MoveNext中的操作如下:   

  •  取了上个对象的迭代器,先做处理。
  • 调用了上个对象的MoveNext对Selector的Func进行了调用,之后再调用this.predicate做筛选。

3.从设计模式的角度

对于List、Dictionary和Array

  • 使用扩展方法扩展扩展IEnumrable的功能,而不修改IEnurable接口内容。
  • 实现新的类对象,持有IEnumrable对象做迭代处理,使用的是组合的方式而不是继承的方式。
  • 新创建的对象分别代表不同的操作,继承同一个父类,因此不同对象之间使用组合模式可以相互组合,实现复杂的操作。

现在又要给这些数据集合添加功能是筛选.实现方法有以下两种:

    1.新写一个接口让这些集合实现,利用迭代的功能实现筛选。坏处是某个对象都需要实现这个方法。破坏了原有类的结构。

    2.由于筛选功能只是用到了迭代器,因此可以:

  • 使用扩展方法扩展扩展IEnumrable的功能,而不修改IEnurable接口内容。
  • 实现新的类对象,持有IEnumrable对象做迭代处理,使用的是组合的方式而不是继承的方式。
  • 新创建的对象分别代表不同的操作,继承同一个父类,因此不同对象之间使用组合模式可以相互组合,实现复杂的操作。

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值