Warning: file_get_contents(/data/phpspider/zhask/data//catemap/2/.net/24.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
C# 如何为独立于对象顺序的对象集合生成唯一哈希_C#_.net_Collections_Equality_Gethashcode - Fatal编程技术网

C# 如何为独立于对象顺序的对象集合生成唯一哈希

C# 如何为独立于对象顺序的对象集合生成唯一哈希,c#,.net,collections,equality,gethashcode,C#,.net,Collections,Equality,Gethashcode,假设我有一节课 public class MyClass { public string Type { get; set; } public int Id { get; set; } } 我有一个集合类,它只是一个强类型列表 public class MyClassList : List<MyClass> { public MyClassList(IEnumerable<MyClass> enumerable) : base (enumerabl

假设我有一节课

public class MyClass
{
    public string Type { get; set; }
    public int Id { get; set; }
}
我有一个集合类,它只是一个强类型列表

public class MyClassList : List<MyClass>
{
    public MyClassList(IEnumerable<MyClass> enumerable) : base (enumerable) {}
}
公共类MyClassList:List
{
公共MyClassList(IEnumerable可枚举):基(可枚举){}
}
我希望
MyClassList
能够基于内容为
MyClassList
生成唯一的哈希代码。
MyClass
的哈希代码应基于这两个属性即使对象的顺序不同,
MyClassList
的哈希代码也应该相同

为了处理排序问题,我想我可以在生成哈希代码之前对列表进行排序,但我不确定如何生成列表的哈希代码。

我提出了这个解决方案(我没有实现Equals方法):

公共类MyClass
{
公共字符串类型{get;set;}
公共int Id{get;set;}
公共覆盖int GetHashCode()
{
int hash=17;
hash=hash+23*this.Type.GetHashCode();
hash=hash+23*this.Id.GetHashCode();
返回散列;
}
}
公共类MyClassList:List
{
公共MyClassList(IEnumerable可枚举):基(可枚举){}
公共覆盖int GetHashCode()
{
返回这个.Aggregate(17,(state,current)=>state*23+current.GetHashCode());
}
}

生成hashcode的方法受Microsoft计算匿名对象的哈希值的方法启发。

clto给出的解决方案有效。这里有一种替代方法:按总排序对列表进行排序(只要不含糊,任何排序都可以)。然后可以使用任何常规方法计算哈希代码。你不需要秩序独立。您甚至可以使用加密哈希函数。

如果顺序不重要,那么您应该使用本质上是集合的集合,而不是列表

此外,通常最好不要从集合继承;用构图代替

因此,对于集合,可以使用
HashSet
,因为它具有set语义

要让
MyClass
使用这两个属性作为它的标识,只需重写它的equals并获得哈希代码实现,或者创建一个
IComparer
,如果您不能或不想这样做的话

public class MyClass:IEquatable<MyClass>
{
    public string Type { get; set; }
    public int Id { get; set; }

    public override bool Equals(object obj)
    {
        return Equals(obj as MyClass);
    }

    public bool Equals(MyClass other)
    {
        if (other == null)
            return false;

        return Type == other.Type &&
            Id == other.Id;
    }

    public override int GetHashCode()
    {
        return Type.GetHashCode() * 79 + Id;
    }
}
公共类MyClass:IEquatable
{
公共字符串类型{get;set;}
公共int Id{get;set;}
公共覆盖布尔等于(对象对象对象)
{
返回等于(obj作为MyClass);
}
公共布尔等于(MyClass其他)
{
如果(其他==null)
返回false;
返回类型==其他.Type&&
Id==other.Id;
}
公共覆盖int GetHashCode()
{
返回类型.GetHashCode()*79+Id;
}
}
那么您的收藏就简单到:

HashSet<MyClass> set = new HashSet<MyClass>();
HashSet=newhashset();
如果您想比较不同的集合,只需使用:

HashSet<MyClass>.CreateSetComparer();
HashSet.CreateSetComparer();

为了获得最佳性能,我会尽量避免每次调用
GetHashCode
时重复整个集合。
GetHashCode
的目的是将性能提高到比评估每个元素更好的程度。因此,当列表中的元素发生如下更改时,我可能会尝试维护哈希代码

class Program
{
  static void Main(string[] args)
  {
     MyClassList l = new MyClassList() { new MyClass() {Type="Bob", Id=1}, new MyClass() {Type="Jones", Id=2}};
     MyClassList l2 = new MyClassList() { new MyClass() { Type = "Jones", Id = 2 }, new MyClass() { Type = "Bob", Id = 1 } };
     MyClassList l3 = new MyClassList() { new MyClass() { Type = "Jones", Id = 2 }};
     Console.WriteLine("{0} {1} {2}", l.GetHashCode(), l2.GetHashCode(), l3.GetHashCode());
     l3.Add(new MyClass() { Type = "Bob", Id = 1 });
     Console.WriteLine("{0}", l3.GetHashCode());
  }
}

public class MyClass
{
  public string Type { get; set; }
  public int Id { get; set; }
  public override int GetHashCode()
  {
     return (Type.GetHashCode() % 0x8000) | (int)((uint)Id.GetHashCode() & 0xFFFF0000);
  }
}

public class MyClassList : IList<MyClass>
{
  List<MyClass> internalList;
  int hashCode = 0;

  public MyClassList()
  {
     internalList = new List<MyClass>();
  }

  private void IncludeInHash(MyClass item)
  {
     hashCode ^= item.GetHashCode();
  }

  private void ExcludeFromHash(MyClass item)
  {
     IncludeInHash(item);
  }

  public override int GetHashCode()
  {
     return hashCode;
  }

  public int IndexOf(MyClass item)
  {
     return internalList.IndexOf(item);
  }

  public void Insert(int index, MyClass item)
  {
     internalList.Insert(index, item);
     // Make sure Insert is successful (doesn't throw an exception) before affecting the hash
     IncludeInHash(item);
  }

  public void RemoveAt(int index)
  {
     MyClass reduce = internalList[index];
     internalList.RemoveAt(index);
     // Make sure RemoveAt is successful before affecting the hash
     ExcludeFromHash(reduce);
  }

  public MyClass this[int index]
  {
     get
     {
        return internalList[index];
     }
     set
     {
        MyClass reduce = internalList[index];
        internalList[index] = value;
        // Make sure these happen atomically; don't allow exceptions to prevent these from being accurate.
        ExcludeFromHash(reduce);
        IncludeInHash(value);
     }
  }

  public void Add(MyClass item)
  {
     internalList.Add(item);
     IncludeInHash(item);
  }

  public void Clear()
  {
     internalList.Clear();
     hashCode = 0;
  }

  public bool Contains(MyClass item)
  {
     return internalList.Contains(item);
  }

  public void CopyTo(MyClass[] array, int arrayIndex)
  {
     internalList.CopyTo(array, arrayIndex);
  }

  public int Count
  {
     get { return internalList.Count; }
  }

  public bool IsReadOnly
  {
     get { return false; }
  }

  public bool Remove(MyClass item)
  {
     if (internalList.Remove(item))
     {
        ExcludeFromHash(item);
        return true;
     }
     else
        return false;
  }

  public IEnumerator<MyClass> GetEnumerator()
  {
     return internalList.AsReadOnly().GetEnumerator();
  }

  System.Collections.IEnumerator System.Collections.IEnumerable.GetEnumerator()
  {
     return GetEnumerator();
  }
}
类程序
{
静态void Main(字符串[]参数)
{
MyClassList l=newmyclasslist(){newmyclass(){Type=“Bob”,Id=1},newmyclass(){Type=“Jones”,Id=2};
MyClassList l2=new MyClassList(){new MyClass(){Type=“Jones”,Id=2},new MyClass(){Type=“Bob”,Id=1};
MyClassList l3=new MyClassList(){new MyClass(){Type=“Jones”,Id=2};
WriteLine(“{0}{1}{2}”,l.GetHashCode(),l2.GetHashCode(),l3.GetHashCode());
添加(newmyclass(){Type=“Bob”,Id=1});
WriteLine(“{0}”,l3.GetHashCode());
}
}
公共类MyClass
{
公共字符串类型{get;set;}
公共int Id{get;set;}
公共覆盖int GetHashCode()
{
返回(Type.GetHashCode()%0x8000)|(int)((uint)Id.GetHashCode()&0xFFFF0000);
}
}
公共类MyClassList:IList
{
名单;
int hashCode=0;
公共MyClassList()
{
internalList=新列表();
}
私有void IncludeInHash(MyClass项目)
{
hashCode^=item.GetHashCode();
}
私有void ExcludeFromHash(MyClass项)
{
IncludeInHash(项目);
}
公共覆盖int GetHashCode()
{
返回哈希码;
}
public int IndexOf(MyClass项)
{
返回internalList.IndexOf(项目);
}
公共void插入(int索引,MyClass项)
{
内部列表。插入(索引,项目);
//在影响哈希之前,确保插入成功(不引发异常)
IncludeInHash(项目);
}
公共无效删除(整数索引)
{
MyClass reduce=内部列表[索引];
internalList.RemoveAt(索引);
//在影响哈希之前,请确保RemoveAt成功
ExcludeFromHash(reduce);
}
公共MyClass此[int索引]
{
得到
{
返回内部列表[索引];
}
设置
{
MyClass reduce=内部列表[索引];
内部列表[索引]=值;
//确保这些事件以原子方式发生;不要允许异常来阻止这些事件的准确性。
ExcludeFromHash(reduce);
IncludeInHash(值);
}
}
公共作废添加(MyClass项目)
{
内部列表。添加(项目);
IncludeInHash(项目);
}
公共空间清除()
{
internalList.Clear();
hashCode=0;
}
公共布尔包含(MyClass项)
{
返回内部列表。包含(项);
}
public void CopyTo(MyClass[]数组,int arrayIndex)
{
CopyTo(数组,arrayIndex);
}
公共整数计数
{
获取{return internalList.Count;}
}
公共图书馆是只读的
{
获取{return false;}
}
公共布尔删除(MyClass项)
{
如果(内部列表。删除(项目))
class Program
{
  static void Main(string[] args)
  {
     MyClassList l = new MyClassList() { new MyClass() {Type="Bob", Id=1}, new MyClass() {Type="Jones", Id=2}};
     MyClassList l2 = new MyClassList() { new MyClass() { Type = "Jones", Id = 2 }, new MyClass() { Type = "Bob", Id = 1 } };
     MyClassList l3 = new MyClassList() { new MyClass() { Type = "Jones", Id = 2 }};
     Console.WriteLine("{0} {1} {2}", l.GetHashCode(), l2.GetHashCode(), l3.GetHashCode());
     l3.Add(new MyClass() { Type = "Bob", Id = 1 });
     Console.WriteLine("{0}", l3.GetHashCode());
  }
}

public class MyClass
{
  public string Type { get; set; }
  public int Id { get; set; }
  public override int GetHashCode()
  {
     return (Type.GetHashCode() % 0x8000) | (int)((uint)Id.GetHashCode() & 0xFFFF0000);
  }
}

public class MyClassList : IList<MyClass>
{
  List<MyClass> internalList;
  int hashCode = 0;

  public MyClassList()
  {
     internalList = new List<MyClass>();
  }

  private void IncludeInHash(MyClass item)
  {
     hashCode ^= item.GetHashCode();
  }

  private void ExcludeFromHash(MyClass item)
  {
     IncludeInHash(item);
  }

  public override int GetHashCode()
  {
     return hashCode;
  }

  public int IndexOf(MyClass item)
  {
     return internalList.IndexOf(item);
  }

  public void Insert(int index, MyClass item)
  {
     internalList.Insert(index, item);
     // Make sure Insert is successful (doesn't throw an exception) before affecting the hash
     IncludeInHash(item);
  }

  public void RemoveAt(int index)
  {
     MyClass reduce = internalList[index];
     internalList.RemoveAt(index);
     // Make sure RemoveAt is successful before affecting the hash
     ExcludeFromHash(reduce);
  }

  public MyClass this[int index]
  {
     get
     {
        return internalList[index];
     }
     set
     {
        MyClass reduce = internalList[index];
        internalList[index] = value;
        // Make sure these happen atomically; don't allow exceptions to prevent these from being accurate.
        ExcludeFromHash(reduce);
        IncludeInHash(value);
     }
  }

  public void Add(MyClass item)
  {
     internalList.Add(item);
     IncludeInHash(item);
  }

  public void Clear()
  {
     internalList.Clear();
     hashCode = 0;
  }

  public bool Contains(MyClass item)
  {
     return internalList.Contains(item);
  }

  public void CopyTo(MyClass[] array, int arrayIndex)
  {
     internalList.CopyTo(array, arrayIndex);
  }

  public int Count
  {
     get { return internalList.Count; }
  }

  public bool IsReadOnly
  {
     get { return false; }
  }

  public bool Remove(MyClass item)
  {
     if (internalList.Remove(item))
     {
        ExcludeFromHash(item);
        return true;
     }
     else
        return false;
  }

  public IEnumerator<MyClass> GetEnumerator()
  {
     return internalList.AsReadOnly().GetEnumerator();
  }

  System.Collections.IEnumerator System.Collections.IEnumerable.GetEnumerator()
  {
     return GetEnumerator();
  }
}