我正在学习编程,我的问题是我有一堆对象,我只想在列表尚未包含该对象的情况下将这些对象添加到列表中。其次,如果对象已经包含,我想忽略该对象并添加下一个对象。我想我的第一部分工作只需要第二部分的帮助。非常感谢。
PartyGroup partyGroup = new PartyGroup();
using (AseDataReader reader = command.ExecuteReader())
{
while (reader.Read())
{
if (!myPartyGroupList.Contains(partyGroup))
{
partyGroup.PartyGroupID = Convert.ToInt32(reader["party_group_id"]);
partyGroup.PartyGroupName = reader["party_group_name"].ToString();
partyGroup.PersonList = myPersonList;
myPartyGroupList.Add(partyGroup);
}
else
{
//??
}
}
}
答案 0 :(得分:5)
你的第一部分完美无缺。
只需删除'else'子句,您的例程将自动在下一次迭代中添加下一个元素。像这样:
while (reader.Read())
{
if (!myPartyGroupList.Contains(partyGroup))
{
partyGroup.PartyGroupID = Convert.ToInt32(reader["party_group_id"]);
partyGroup.PartyGroupName = reader["party_group_name"].ToString();
partyGroup.PersonList = myPersonList;
myPartyGroupList.Add(partyGroup);
}
}
答案 1 :(得分:4)
您的代码存在一些问题。首先,您为每个迭代重用相同的对象。
考虑
List<Foo> foos = new List<Foo>();
Foo foo = new Foo();
foo.Bar = "Alpha";
foos.Add(foo);
foo.Bar = "Beta";
foos.Add(foo);
您会注意到您的列表将包含2个项目,但它们将引用同一个对象。如果您遍历列表并检查Bar
,则每个都会返回"Beta"
。
您想为每件商品创建新 Foo
。
List<Foo> foos = new List<Foo>();
Foo foo = new Foo();
foo.Bar = "Alpha";
foos.Add(foo);
Foo anotherFoo = new Foo();
anotherFoo.Bar = "Beta";
foos.Add(anotherFoo);
在循环术语中,这基本上只意味着在循环内而不是外部创建对象。
while (someCondition)
{
Foo foo = new Foo();
// do your work, populate the object, etc.
// then check contains
if (!myList.Contains(foo))
myList.Add(foo);
}
关于检查集合是否已包含该对象,您是否正确覆盖了Equals
和GetHashCode
?处理类时,默认行为是简单地检查对象引用是否相等。如果您担心对象是封装的值,那么您需要自己提供逻辑。在您的课程中,您需要覆盖Equals
和GetHashCode
方法,以实现所需的确定相等的方法。
class Foo
{
public string Bar { get; set; }
public override int GetHashCode()
{
return this.Bar.GetHashCode();
}
public override bool Equals(object other)
{
Foo otherFoo = other as Foo;
if (otherFoo == null)
return false;
else
return this.Bar == otherFoo.Bar;
}
}
现在当Contains
试图确定对象是否已经在列表中时,它将根据对象中包含的值而不是内存引用来执行此操作。
答案 2 :(得分:3)
比较时,最好使用与标识符的比较,在您的情况下是PartyGroupId。如果使用contains然后是Contains()的默认重载,那么列表中对象的哈希值将用于比较。
因此,不是将比较保留给.NET,您可以创建自定义IEqualityComparer实现或使用Linq的Where子句,如下所示。
using (AseDataReader reader = command.ExecuteReader())
{
while (reader.Read())
{
int groupId = Convert.ToInt32(reader["party_group_id"]);
if (partyGroupsList.Where(partyGroup => partyGroup.PartyGroupID == groupId).Any() == false)
{
PartyGroup newPartyGroup = new PartyGroup()
{
PartyGroupID = groupId,
PartyGroupName = reader["party_group_name"].ToString(),
PersonList = myPersonList
};
partyGroupsList.Add(newPartyGroup);
}
// If object already exists in the list then do not add, continue
// to the next row.
}
}
另一个建议是将PartyGroup类成员重命名为:
class PartyGroup
{
public int ID { get; set; }
public string Name { get; set; }
public IList PersonList { get; set; }
}
答案 3 :(得分:1)
您可以考虑使用Hashset<PartyGroup>
填充,然后将其转换为列表。如果你有大量的项目,那将比检查每个项目的列表快得多。
Hashset<PartyGroup> pgHash = new Hashset<PartyGroup>();
using (AseDataReader reader = command.ExecuteReader())
{
while (reader.Read())
{
PartyGroup pg = new PartyGroup();
partyGroup.PartyGroupID = Convert.ToInt32(reader["party_group_id"]);
partyGroup.PartyGroupName = reader["party_group_name"].ToString();
partyGroup.PersonList = myPersonList;
// Add won't add an item if it already exists in the collection.
pgHash.Add(partyGroup);
}
}
// Now convert the result to a list.
myPartyGroupList = pgHash.ToList();
如果您的PartyGroup
类未实现IEquatable<PartyGroup>
,则必须提供相等比较器。以下应该有效:
public class PartyGroupComparer:IEqualityComparer<PartyGroup>
{
public bool Equals(PartyGroup g1, PartyGroup g2)
{
return g1.PartyGroupId.Equals(g2.PartyGroupId);
}
public int GetHashCode(PartyGroup g)
{
return g.PartyGroupId;
}
}
然后你的初始化变为:
IEqualityComparer<PartyGroup> pgComparer = new PartyGroupComparer();
HashSet<PartyGroup> pgHash = new HashSet<PartyGroup>(pgComparer);
正如其他人所指出的,HashSet
的替代方案是Dictionary
。这将阻止您必须进行相等比较。完成后,您仍然需要转换为列表。但这很简单:
Dictionary<int, PartyGroup> dict = new Dictionary<int, PartyGroup>();
// populate dictionary as suggested in other answer
// now convert values to a list.
myPartyGroupList = dict.Values.ToList();
答案 4 :(得分:0)
试试这个
while (reader.Read())
{
partyGroup.PartyGroupID = Convert.ToInt32(reader["party_group_id"]);
partyGroup.PartyGroupName = reader["party_group_name"].ToString();
partyGroup.PersonList = myPersonList;
if (!myPartyGroupList.Contains(partyGroup))
{
myPartyGroupList.Add(partyGroup);
}
}
答案 5 :(得分:0)
首先,您要检查对象实例是否在集合中,但您只创建一个实例(在while循环之外)。因此,当您检查!myPartyGroupList.Contains(partyGroup)
时,它将在第一次返回false,因此您将obj添加到集合中,然后每次都返回false。
我会使用一个使用Id属性的Dictionary作为Dictionary键。
像这样:Dictionary <int,PartyGroup> myPartyGroupList = new Dictionary <int,PartyGroup>();
using (AseDataReader reader = command.ExecuteReader())
{
while (reader.Read())
{
int id=Convert.ToInt32(reader["party_group_id"]);
if (!myPartyGroupList.ContainsKey( id ))
{
PartyGroup partyGroup = new PartyGroup();
partyGroup.PartyGroupID = id;
partyGroup.PartyGroupName = reader["party_group_name"].ToString();
partyGroup.PersonList = myPersonList;
myPartyGroupList.Add(id, partyGroup); // key, value? check param order here
}
}
}