自定义集合类型(续)

简介:

在前一篇博文中,我们自定义了类型User和它的集合类Users,实现对这个集合的添加,删除,检索,修改(是先检索出单个User,然后直接修改这个检索出来的值,这是因为User是引用类型)。在上一篇博文中,我们是做了个索引器,通过用户的ID来作为索引的条件。其实在我们在做查询时,不只只是需要UserID作为查询条件,可能需要UserName,有时不只只是一个件条,有可能是两个条件,如果有一个我们随心所欲的查询就好了。

其实我们组合c#的一些知识,来实现这个功能:
首先定义一个委托:
    delegate bool Fun(User user);
这个委托是接收一个User类型的参数,以一个bool类型作为返回值。
再次在Users集合类中定义一个查询方法:
       public User First(Fun predicate)
        {
            foreach (User user in users)
            {
                if (predicate(user))
                {
                    return user;
                }
            }
            return null;
        }
方法的参数是接收一个Fun的委托类型,也就是一个方法,参数predicate在First内就代表一个方法,First方法体是循环Users内users这个泛型的List集合,把每个子项当参数传进predicate方法,如果predicate方法返回值为true,就把这个泛型集合的中的User当成First方法的返回值返回去,总而言之,First方法是从集合查找满足predicate方法的用户,并返回。
再次,我们来使用一下Users中的这个First方法:
应用程序中创建代码如下:
Users users =  new Users();
            User user1 = new User();
            user1.ID = 1;
            user1.UserName = "张三";
            user1.PassWord = "111111";
            users.AddUser(user1);
 
            User user2 = new User();
            user2.ID = 2;
            user2.UserName = "李四";
            users.AddUser(user2);
 
            MessageBox.Show(users.First(user => user.ID == 1).ToString());//这是在WinForm下面的显示
user => user.ID == 1代表一个方法,不过是匿名方法,前面一个user是参数,后面的user.ID==1的返回值作为匿名方法的返回值,这个匿名方法,与委托Fun正好对应上,即参数是User,返回值是bool。
当然,user=>user.ID==1只是一种写法,我们还可以写成user=>user.UserName==”aaaa”,或写成user=>user.UserNmae==”aaaa”&&user.PassWord==”111111”,“=>”符号右边的表达式只要是个bool类型就可以。正是因为这个匿名方法,我们查询的条件就变成灵活的了,而不用专门定义不同类型的查询方法来适应不同的查询了。
也可能,这时,你已经想到,在LINQ中,也是这样实现的,对,这种写法与LINQ中的查询语法是一样的。
不过,在LINQ中,这些扩展了的查询语法的方法,不是在具体的某一个集合类中定义的,而是在一个静态类中定义的,这个静态类叫Enumerable,它是一个扩展方法的类,内部包括很多个扩展方法,比如内部的 First方法,它是给实现了IEnumerable<T>接口的类扩展的一个方法,只要实现这个接口的类,就能调用这些查询语法的扩展方法。我们在使用数组时可以使用查询语法的方法,在List<T>集合中也可以,这都是因为它们都实现了IEnumerable<T>的接口。
换言之,如果我们把Users也实现IEnumerable<T>接口,Users也自然就拥有像First,Where这些查询语法的方法了。而不像上面那样(Users类中的First方法),需要自己一个一个去实现所有的扩展方法了。
但由于IEnumerable<T>是个泛型的接口,把以Users类也就需要定义成泛型了,为了使Users专用,我们在Users定义时,使用了泛型的约束,T是User类,或它的子类都可以。
class  Users<T> : IEnumerable<T>, IListSource, IEnumerable where T : User
    {
        /// <summary>
        /// 实现Ienumerable<T>的GetEnumerator方法
        /// </summary>
        /// <returns></returns>
        IEnumerator<T> IEnumerable<T>.GetEnumerator()
        {
            for (int i = 0; i < users.Count; i++)
            {
                yield return users[i];
            }
        }
 
        /// <summary>
        /// 用户集合
        /// </summary>
        List<T> users = new List<T>();
        /// <summary>
        /// 用户
        /// </summary>
        /// <param name="i">用户ID</param>
        /// <returns></returns>
        public T this[int ID]
        {
            get
            {
                foreach (T user in users)
                {
                    if (Convert.ToInt32(user.GetType().GetProperty("ID").GetValue(user, null)) == ID)
                    {
                        return user;
                    }
                }
                return default(T);
            }
            set
            {
                for (int i = 0; i < users.Count; i++)
                {
                    if (Convert.ToInt32(users[i].GetType().GetProperty("ID").GetValue(users[i], null)) == (Convert.ToInt32(value.GetType().GetProperty("ID").GetValue(value, null))))
                    {
                        users[i] = value;
                    }
                }
             }
        }
 
        /// <summary>
        /// 添加用户
        /// </summary>
        /// <param name="user">用户</param>
        public void AddUser(T user)
        {
            users.Add(user);
        }
        /// <summary>
        /// 移除用户
        /// </summary>
        /// <param name="user">用户</param>
        public void RemoveUser(T user)
        {
            users.Remove(user);
        }
        /// <summary>
        /// 获得用户数量
        /// </summary>
        public int Count
        {
            get
            {
                return users.Count;
            }
        }
        /// <summary>
        /// 是否包含List
        /// </summary>
        public bool ContainsListCollection
        {
            get { return true; }
        }
        /// <summary>
        /// 返回集合
        /// </summary>
        /// <returns></returns>
        public System.Collections.IList GetList()
        {
            return users;
        }
        /// <summary>
        /// 实现对users的foreach遍历
        /// </summary>
        /// <returns></returns>
        public IEnumerator GetEnumerator()
        {
            for (int i = 0; i < users.Count; i++)
            {
                yield return users[i];
            }
        }
    }
其实如果限制了T为User类或它的子类,在一定程度上这个Users类的使用就很受限制了,如果不限制T受User约束,那么Users就不一定是User的集合了,因为T决定了这个集合是什么类型的集合,此时的Users<T>更像List<T>了(Users<T>中的成员,还是要少于List<T>中的成员的,因数在Users<T>中我们仅定义了Add,Remove,Count,索引器等成员)。
通过上面的例子,我们能了解到,查询条件可以自定义,也可以通过继承IEnumerable<T>接口来扩展查询,这要根据自己的应用决定使用那一技术了。

















本文转自桂素伟51CTO博客,原文链接:http://blog.51cto.com/axzxs/534778  ,如需转载请自行联系原作者

相关文章
|
9月前
tuple定义的两种方式以及两种操作方法
tuple定义的两种方式 定义一个元素的元组 定义空元组的两种方式 tuple类型的两个操作方法的使用
39 0
|
9月前
|
存储 安全 Java
集合和泛型的详细讲解(二)
集合和泛型的详细讲解
71 0
|
9月前
|
存储 算法 Java
集合和泛型的详细讲解(一)
集合和泛型的详细讲解
44 0
|
9月前
|
Java
2.3 Lambda表达式在集合操作中的应用:对集合元素进行映射和转换
2.3 Lambda表达式在集合操作中的应用:对集合元素进行映射和转换
95 0
|
10月前
|
存储 C# 索引
C#泛型集合常用方法
C#泛型集合常用方法
46 0
|
10月前
对象添加自定义键值对
对象添加自定义键值对
|
存储 Java 索引
8、集合和泛型
堆栈:先进后出,像个容器,入口和出口都是栈顶、压栈和弹栈都是操作栈顶元素 队列:先进先出、队列的入口和出口各占一侧 数组:通过索引查找元素速度快;增删元素速度慢 链表:多节点之间通过地址连接,增删只需要修改下个元素的地址速度比较快,没有索引位置查找速度比较慢
47 0
C#编程-107:泛型集合接口概述
C#编程-107:泛型集合接口概述
C#编程-107:泛型集合接口概述
GoogleGuava - 第 2 章 集合——新集合类型
GoogleGuava - 第 2 章 集合——新集合类型
91 0
GoogleGuava - 第 2 章 集合——新集合类型
GoogleGuava - 第 2 章 集合——集合扩展工具类
GoogleGuava - 第 2 章 集合——集合扩展工具类
74 0
GoogleGuava - 第 2 章 集合——集合扩展工具类