【发布时间】:2009-03-28 19:09:31
【问题描述】:
这是我在使用Except 运算符时注意到的一个有趣问题:
我有想要排除某些用户的用户列表:
用户列表来自一个 XML 文件:
代码如下:
interface IUser
{
int ID { get; set; }
string Name { get; set; }
}
class User: IUser
{
#region IUser Members
public int ID
{
get;
set;
}
public string Name
{
get;
set;
}
#endregion
public override string ToString()
{
return ID + ":" +Name;
}
public static IEnumerable<IUser> GetMatchingUsers(IEnumerable<IUser> users)
{
IEnumerable<IUser> localList = new List<User>
{
new User{ ID=4, Name="James"},
new User{ ID=5, Name="Tom"}
}.OfType<IUser>();
var matches = from u in users
join lu in localList
on u.ID equals lu.ID
select u;
return matches;
}
}
class Program
{
static void Main(string[] args)
{
XDocument doc = XDocument.Load("Users.xml");
IEnumerable<IUser> users = doc.Element("Users").Elements("User").Select
(u => new User
{ ID = (int)u.Attribute("id"),
Name = (string)u.Attribute("name")
}
).OfType<IUser>(); //still a query, objects have not been materialized
var matches = User.GetMatchingUsers(users);
var excludes = users.Except(matches); // excludes should contain 6 users but here it contains 8 users
}
}
当我打电话给User.GetMatchingUsers(users) 时,我得到了预期的 2 场比赛。
问题是当我打电话给users.Except(matches) 时,匹配的用户根本没有被排除在外!我期待 6 个用户,但“排除”包含所有 8 个用户。
因为我在GetMatchingUsers(IEnumerable<IUser> users) 所做的一切就是使用IEnumerable<IUser> 并返回
IUsers 的 ID 匹配(在这种情况下为 2 个 IUsers),我的理解是默认情况下 Except 将使用引用相等
用于比较要排除的对象。这不是Except 的行为方式吗?
更有趣的是,如果我使用.ToList()实现对象,然后获取匹配的用户,并调用Except,
一切都按预期进行!
像这样:
IEnumerable<IUser> users = doc.Element("Users").Elements("User").Select
(u => new User
{ ID = (int)u.Attribute("id"),
Name = (string)u.Attribute("name")
}
).OfType<IUser>().ToList(); //explicity materializing all objects by calling ToList()
var matches = User.GetMatchingUsers(users);
var excludes = users.Except(matches); // excludes now contains 6 users as expected
鉴于在IEnumerable<T> 上定义,我不明白为什么我需要物化对象来调用Except?
任何建议/见解将不胜感激。
【问题讨论】: