在前一篇博文中,我们自定义了类型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
,如需转载请自行联系原作者