zoukankan      html  css  js  c++  java
  • 21扩展IEnumerable<T>泛型接口自定义LINQ的扩展方法

    LINQ方法实际上是对IEnumerable<TSource>的扩展,如图:

    2

     

    本篇自定义一个MyWhere方法,达到与Where相同的效果。

     

      使用LINQ自带的Where方法

        class Program
        {
            static void Main(string[] args)
            {
                List<int> list = new List<int>(){1, 2, 3};
                IEnumerable<int> query = list.Where(x => x%2 == 0);
                list.Add(4);
                showConsole(query);
                Console.ReadKey();
            }
     
            private static void showConsole<T>(IEnumerable<T> list)
            {
                foreach (T item in list)
                {
                    Console.WriteLine(item.ToString());
                }
            }
        }

     

    结果:

    1

     

    这样的结果符合LINQ的"延迟加载"的特点,虽然是在IEnumerable<int> query = list.Where(x => x%2 == 0)之后为集合添加元素list.Add(4),但直到调用showConsole(query)遍历,查询才真正执行。

     

      自定义一个MyWhere,无延迟加载

    □ 首先想到的是对IEnumerable<TSource>的扩展,创建静态方法和静态类。

     public static class Extension
        {
            //Func<TSource, bool>是委托,返回的是bool类型 
            public static IEnumerable<TSource> MyWhere<TSource>(this IEnumerable<TSource> source,
                Func<TSource, bool> predicate)
            {
                if(source==null) throw new ArgumentException();
                if(predicate==null) throw new ArgumentException();
                List<TSource> result = new List<TSource>();
                foreach (TSource item in source)
                {
                    if (predicate(item))
                    {
                        result.Add(item);
                    }
                }
                return result;
            }
        }


    □ 执行主程序

        class Program
        {
            static void Main(string[] args)
            {
                List<int> list = new List<int>(){1, 2, 3};
                IEnumerable<int> query = list.MyWhere(x => x % 2 == 0);
                list.Add(4);
                showConsole(query);
                Console.ReadKey();
            }
     
            private static void showConsole<T>(IEnumerable<T> list)
            {
                foreach (T item in list)
                {
                    Console.WriteLine(item.ToString());
                }
            }
        }

     

    □ 结果  

    3

     

    这样的结果丢掉了LINQ的"延迟加载"的特点,也就是后加元素list.Add(4)之后,没有再对集合进行遍历。

    可希望的结果是:
    ● 后加元素list.Add(4)之后,还需要遍历集合
    ● 返回结果还是IEnumerable<TSource>类型

     

    于是,想到了Decorator设计模式,使用它能满足以上2个条件。

     

      自定义一个MyWhere,也有延迟加载,使用Decorator设计模式

     

    ● 为了返回IEnumerable<TSource>类型,必须让装饰者类实现IEnumerable<T>接口
    ● 装饰者类最重要的特点是包含目标参数类型的引用
    ● 为了能遍历,装饰者类内部还包含了一个迭代器

     

       public class WhereDecorator<T> : IEnumerable<T>
        {
            private IEnumerable<T> list;
            private Func<T, bool> predicate;
     
            public WhereDecorator(IEnumerable<T> list, Func<T, bool> predicate)
            {
                this.list = list;
                this.predicate = predicate;
            }
     
            public IEnumerator<T> GetEnumerator()
            {
                return new WhereEnumerator<T>(list, predicate);
            }
     
            System.Collections.IEnumerator System.Collections.IEnumerable.GetEnumerator()
            {
                return new WhereEnumerator<T>(list, predicate);
            }
     
            public class WhereEnumerator<T> : IEnumerator<T>
            {
                private List<T> innerList;
                private int index;
     
                public WhereEnumerator(IEnumerable<T> list, Func<T, bool> predicate)
                {
                    innerList = new List<T>();
                    index = -1;
                    foreach (T item in list)
                    {
                        if (predicate(item))
                        {
                            innerList.Add(item);
                        }
                    }
                }
     
                public T Current
                {
                    get { return innerList[index]; }
                }
     
                public void Dispose()
                {
                    
                }
     
                object System.Collections.IEnumerator.Current
                {
                    get { return innerList[index]; }
                }
     
                public bool MoveNext()
                {
                    index++;
                    if (index >= innerList.Count)
                    {
                        return false;
                    }
                    else
                    {
                        return true;
                    }
                }
     
                public void Reset()
                {
                    index = -1;
                }
            }
        }
     

     

    自定义MyWhere中,现在可以使用装饰者类来返回一个实例。

        public static class Extension
        {
            public static IEnumerable<TSource> MyWhere<TSource>(this IEnumerable<TSource> source,
                Func<TSource, bool> predicate)
            {
                if(source==null) throw new ArgumentException();
                if(predicate==null) throw new ArgumentException();
                return new WhereDecorator<TSource>(source, predicate);
            }
        }    

     

    主程序中:

        class Program
        {
            static void Main(string[] args)
            {
                List<int> list = new List<int>(){1, 2, 3};
                IEnumerable<int> query = list.MyWhere(x => x % 2 == 0);
                list.Add(4);
                showConsole(query);
                Console.ReadKey();
            }
     
            private static void showConsole<T>(IEnumerable<T> list)
            {
                foreach (T item in list)
                {
                    Console.WriteLine(item.ToString());
                }
            }
        }

     

    结果:

    1


    可见,与LINQ的Where方法返回结果一样。

     

      总结

     

    ● 所有的LINQ方法是对IEnumerable<T>的扩展
    ● 当我们想对方法返回的结果再进行链式操作的时候,装饰者类就包含方法参数类型的引用并返回与该方法相同的类型。
    ● 这里的装饰者类需要完成遍历,装饰者类必须实现IEnumerable<T>,内部必须存在迭代器实现IEnumerator<T>接口。

  • 相关阅读:
    2019/1/17 break语句小练习
    2019/1/17goto语句小试牛刀
    python 中* 和**的作用
    python 元组编码和解码问题
    python SMTP 发送邮件
    python 自定义异常
    python websocket client 使用
    excel、xls文件读写操作
    windows10局域网实现文件共享
    django入门
  • 原文地址:https://www.cnblogs.com/darrenji/p/3637428.html
Copyright © 2011-2022 走看看