C# Hashset未添加重复项,但为Add()返回true
(编辑)更多信息。第一个通知是“新虚拟”。这个类继承了一个基类,这个基类应该是一个通用的父类,可以用任何ICollection类型创建。这是描述词,基本上是:C# Hashset未添加重复项,但为Add()返回true,c#,C#,(编辑)更多信息。第一个通知是“新虚拟”。这个类继承了一个基类,这个基类应该是一个通用的父类,可以用任何ICollection类型创建。这是描述词,基本上是: public abstract class ParentAwareCollection<TObject, TParent, TInnerList> : ICollection<TObject>, ICollection, IParentProvider<TParent> where TObje
public abstract class ParentAwareCollection<TObject, TParent, TInnerList> :
ICollection<TObject>, ICollection, IParentProvider<TParent>
where TObject : IParentProvider<TParent>
where TInnerList : ICollection<TObject>, new()
{
protected TInnerList InnerList = new TInnerList();
...
}
请注意,在中实现的ICollection与我的一样。这就是为什么我相信这样做是可以的。但是,与我的不同,框架HashSet没有为其Add()方法使用new
描述符,但这是必需的,因为ICollection
实现了void Add(T项)
。也许他们只是漏掉了
原始问题:
我有一个collection类,它使用HashSet
存储其对象。类型为T的对象覆盖GetHashCode()
,其中它们确保存在用于生成哈希代码的某些必需信息。我不确定这是否重要
当我向HashSet添加(T)时,它不会添加对象,而是返回true。如果我调试,然后在即时窗口中再次尝试添加它,它将返回false,就像它应该的那样。方法如下所示:
public new virtual bool Add(TObject item)
{
// Must add parent first, since it may be used in the hash code
// InnerList is a HashSet<T>
if (InnerList.Any(existing=>item.GetHashCode()==existing.GetHashCode())) {
return(false);
} else {
if (InnerList.Add(item))
{
return(true);
} else {
return(false);
}
}
}
public new virtual bool Add(TObject item)
{
return InnerList.Add(item);
}
单步遍历InnerList.Add(),它返回true:
?InnerList.Count
1
?InnerList.Add(item)
false
Wtf?这是.net 4.0 framework。您的
添加的代码错误:
public new virtual bool Add(TObject item)
{
// Must add parent first, since it may be used in the hash code
// InnerList is a HashSet<T>
if (InnerList.Any(existing=>item.GetHashCode()==existing.GetHashCode())) {
return(false);
} else {
if (InnerList.Add(item))
{
return(true);
} else {
return(false);
}
}
}
您的添加代码错误:
public new virtual bool Add(TObject item)
{
// Must add parent first, since it may be used in the hash code
// InnerList is a HashSet<T>
if (InnerList.Any(existing=>item.GetHashCode()==existing.GetHashCode())) {
return(false);
} else {
if (InnerList.Add(item))
{
return(true);
} else {
return(false);
}
}
}
我知道了。这是一件非常阴险的小事。因此,这个设置的全部要点是,我可以拥有一个具有“父级”的集合类,当您向集合中添加项时,它们会自动分配给该父级。(这个父对象不仅仅是类本身,它是另一个对象)
问题是:
CsmResourceHashSet resources = new CsmResourceHashSet(Context);
resources.AddFrom(Context.ScriptResources
.Where(item=>item.Enabled));
CsmResourceHashSet
是一个parentawarhashset
。扩展方法AddFrom:
public static void AddFrom<T>(this ICollection<T> destList, IEnumerable<T> sourceList)
{
foreach (T obj in sourceList)
{
destList.Add(obj);
}
}
一旦我这么做了,它就起作用了。嗯,实际上它不起作用,但它揭示了一对疯狂的小错误,它们大多没有表现出来,但我所有的异常开始到处爆发,而且没有花时间修复它们。我找到了答案。这是一件非常阴险的小事。因此,这个设置的全部要点是,我可以拥有一个具有“父级”的集合类,当您向集合中添加项时,它们会自动分配给该父级。(这个父对象不仅仅是类本身,它是另一个对象)
问题是:
CsmResourceHashSet resources = new CsmResourceHashSet(Context);
resources.AddFrom(Context.ScriptResources
.Where(item=>item.Enabled));
CsmResourceHashSet
是一个parentawarhashset
。扩展方法AddFrom:
public static void AddFrom<T>(this ICollection<T> destList, IEnumerable<T> sourceList)
{
foreach (T obj in sourceList)
{
destList.Add(obj);
}
}
一旦我这么做了,它就起作用了。嗯,实际上它不起作用,但它揭示了一对疯狂的小错误,它们大多没有表现出来,但我所有的异常开始到处爆发,而且没有时间修复它们。也许你可以发布一个“准备运行”的代码示例,允许重现这个问题?否则很难猜测问题在哪里……TObject的定义是什么?我们如何复制它?有很多代码。。。我会把基类放上去。请查看我的编辑。不过,我并不完全理解它,因为我正在调用InnerList.Add,所以我不明白为什么基类Add会被调用,而且它没有返回,我将尝试几件事情……请注意,您不应该假设哈希代码是唯一的。您应该依次覆盖GetHashCode
和Equals
<可以说,code>GetHashCode
是验证的第一项。如果它们不匹配,则假设等于
也将是错误的。但由于GetHashCode
不能保证唯一性,匹配的哈希代码并不意味着等于真。简言之,哈希集将首先检查哈希代码,如果合适,检查等于
,并且您也不应该仅仅基于哈希代码匹配而拒绝添加
。@Jamiere:Gotcha。你不会从多个线程调用这个方法吧?也许你可以发布一个“ready to run”(准备运行)的代码示例来重现这个问题?否则很难猜测问题在哪里……TObject的定义是什么?我们如何复制它?有很多代码。。。我会把基类放上去。请查看我的编辑。不过,我并不完全理解它,因为我正在调用InnerList.Add,所以我不明白为什么基类Add会被调用,而且它没有返回,我将尝试几件事情……请注意,您不应该假设哈希代码是唯一的。您应该依次覆盖GetHashCode
和Equals
<可以说,code>GetHashCode
是验证的第一项。如果它们不匹配,则假设等于
也将是错误的。但由于GetHashCode
不能保证唯一性,匹配的哈希代码并不意味着等于真。简言之,哈希集将首先检查哈希代码,如果合适,检查等于
,并且您也不应该仅仅基于哈希代码匹配而拒绝添加
。@Jamiere:Gotcha。您不会从多个线程调用此方法吧?正如我所说,我添加了第一个检查,因为它不适用于InnerList.Add()。问题是HashSet.Add()正在添加并返回true,即使它没有添加项。我确实意识到我也需要检查Equals,但这只会导致误判,而不是我遇到的问题。快速查看HashSet。使用reflector添加验证这是不可能的。可能是其他线程在检查之前删除了该项,或者是调试器在耍花招-尝试打印是的,这不是HashSet的错,但这里有点让人困惑,请参阅我的答案。正如我所说,我添加了第一个检查,因为它不只是与InnerList.Add()一起工作。问题是HashSet.Add()正在添加并返回true,即使它没有添加项。我确实意识到我也需要检查Equals,但这只会导致误判,而不是我遇到的问题。快速查看HashSet.Addpublic static void AddFrom<T>(this ISet<T> destList, IEnumerable<T> sourceList)
{
foreach (T obj in sourceList)
{
destList.Add(obj);
}
}