C#中的Where的使用

一、约束

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

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

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

二、集合条件查询

1.使用方法

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

2.如何实现的

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

 //返回值是IEnumerable迭代器对象

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

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

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

我们可查看 WhereListIterator 这个类,它继承了:Enumerable.IteratorIEnumerable .其本身实现了迭代器的功能,查看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对象返回。只不过构造函数是使用集合做的初始化,如下:

    [__DynamicallyInvokable]

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

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

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

我们还可以做如下操作:

var  whereListIt  = list.Where((b) => b.value >1) 
 Func 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:IEnumerable
  2. WhereListIterator:Enumerable.Iterator:IEnumerable

  所以有连续的操作如:

list.Where((b) => b.value == 2).where((b) => b.value == 2)
Func 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 Select(
        Func selector) {
        return (IEnumerable) new Enumerable.SelectEnumerableIterator(this._source, Enumerable.CombineSelectors(this._selector, selector));
}
组合操作做了组合:下面是Selector.Where的组合操作
public override IEnumerable Where(Func predicate) => (IEnumerable) new Enumerable.WhereEnumerableIterator((IEnumerable) this, predicate);

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

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

3.从设计模式的角度

对于List、Dictionary和Array

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

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

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

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

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

 

你可能感兴趣的:(C#)