C# 重载Linq,但允许使用字节数组的自定义结构除外
我在自定义结构和重载linq的except方法以删除重复项方面遇到问题 我的结构如下:C# 重载Linq,但允许使用字节数组的自定义结构除外,c#,linq,struct,operator-overloading,except,C#,Linq,Struct,Operator Overloading,Except,我在自定义结构和重载linq的except方法以删除重复项方面遇到问题 我的结构如下: public struct hashedFile { string _fileString; byte[] _fileHash; public hashedFile(string fileString, byte[] fileHash) { this._fileString = fileString; this._fileHash = file
public struct hashedFile
{
string _fileString;
byte[] _fileHash;
public hashedFile(string fileString, byte[] fileHash)
{
this._fileString = fileString;
this._fileHash = fileHash;
}
public string FileString { get { return _fileString; } }
public byte[] FileHash { get { return _fileHash; } }
}
现在,以下代码可以正常工作:
public static void test2()
{
List<hashedFile> list1 = new List<hashedFile>();
List<hashedFile> list2 = new List<hashedFile>();
hashedFile one = new hashedFile("test1", BitConverter.GetBytes(1));
hashedFile two = new hashedFile("test2", BitConverter.GetBytes(2));
hashedFile three = new hashedFile("test3", BitConverter.GetBytes(3));
hashedFile threeA = new hashedFile("test3", BitConverter.GetBytes(4));
hashedFile four = new hashedFile("test4", BitConverter.GetBytes(4));
list1.Add(one);
list1.Add(two);
list1.Add(threeA);
list1.Add(four);
list2.Add(one);
list2.Add(two);
list2.Add(three);
List<hashedFile> diff = list1.Except(list2).ToList();
foreach (hashedFile h in diff)
{
MessageBox.Show(h.FileString + Environment.NewLine + h.FileHash[0].ToString("x2"));
}
}
publicstaticvoidtest2()
{
List list1=新列表();
List list2=新列表();
hashedfileone=新的hashedFile(“test1”,BitConverter.GetBytes(1));
hashedFile two=新的hashedFile(“test2”,BitConverter.GetBytes(2));
hashedFile三=新的hashedFile(“test3”,BitConverter.GetBytes(3));
hashedFile threeA=新的hashedFile(“test3”,BitConverter.GetBytes(4));
hashedFile-four=新的hashedFile(“test4”,BitConverter.GetBytes(4));
清单1.增加(一);
清单1.添加(两个);
清单1.添加(a);
清单1.添加(四个);
清单2.添加(一个);
清单2.添加(两个);
清单2.添加(三个);
List diff=list1.Except(list2.ToList();
foreach(不同格式的hashedh文件)
{
Show(h.FileString+Environment.NewLine+h.FileHash[0].ToString(“x2”);
}
}
这段代码显示“3A”和“4”很好。但是如果我做了下面的事情
public static List<hashedFile> list1(var stuff1)
{
//Generate a List here and return it
}
public static List<hashedFile> list2(var stuff2)
{
//Generate a List here and return it
}
List<hashedFile> diff = list1.except(list2);
公共静态列表列表1(变量1)
{
//在这里生成一个列表并返回它
}
公共静态列表列表2(变量2)
{
//在这里生成一个列表并返回它
}
List diff=list1。除(list2)外;
“diff”成为“list1”的精确副本。我还应该提到,我正在从System.Security.Cryptography.MD5将ComputeHash中的字节数组发送到列表中的字节文件哈希
关于如何为linq重载Except或GetHashCode方法以成功地从列表2中排除重复值,您有什么想法吗
我真的很感激!谢谢
~z~弗里曼先生
编辑:这里是我最初尝试使用List diff=newList.Except(oldList,newhashedfilecomparer()).ToList()的方法代码>
类hashedFileComparer:IEqualityComparer
{
公共布尔等于(哈希文件x,哈希文件y)
{
if(Object.ReferenceEquals(x,y))返回true;
if(Object.ReferenceEquals(x,null)| | Object.ReferenceEquals(y,null))
返回false;
返回x.FileString==y.FileString&&x.FileHash==y.FileHash;
}
public int GetHashCode(hashedFile hashedFile)
{
if(Object.ReferenceEquals(Hashedfile,null))返回0;
int hashFileString=Hashedfile.FileString==null?0:Hashedfile.FileString.GetHashCode();
int hashFileHash=Hashedfile.FileHash.GetHashCode();
int returnVal=hashFileString^hashFileHash;
if(Hashedfile.FileString.Contains(“blankmusic”)==true)
{
Console.WriteLine(returnVal.ToString());
}
返回值;
}
}
如果希望类型在中处理其自身的比较,则需要的接口是IEquatable。IEqualityComparer接口将让另一个类型处理比较,以便将其作为重载传递到中
这实现了您想要的(假设您想要比较文件字符串和散列)
根据性能要求,修复此问题的方法是只返回0哈希代码。这意味着将始终使用比较器
public override int GetHashCode()
{
return 0;
}
另一个选择是生成一个适当的哈希代码,这比我预期的要快。500个项目的差异是7ms vs 1ms,5000个项目的差异是650ms vs 13ms。因此,最好使用适当的哈希代码。字节数组哈希代码函数取自
public override int GetHashCode()
{
var hashCode=0;
var bytes=_fileHash.Union(Encoding.UTF8.GetBytes(_fileString)).ToArray();
for(var i=0;i(29))^bytes[i];//按3位旋转并对新值进行异或运算。
返回哈希码;
}
如果上面的HashedFile
类型的代码是您所拥有的全部,那么行为是预期的,因为没有相等的/GetHashCode
(因为数组和其他.Net集合不是按值比较的-所以您需要自己编写)。旁注:使用struct
通常是个人的选择当你想要一些痛苦的时候,一定要明白你在做什么。我超载了我自己的iQualityComparer,但它产生了完全相同的结果。事实上,在使用Except方法时,单步遍历代码时,它甚至从未触及重载的“Equals”。为什么HashedFile
是一个结构体?我看不到您的GetHashCode
,因此很难说哈希代码匹配失败的原因(因此没有调用Equal
).我使用结构而不是类,因为我在程序中使用类似的类时发现了一些性能问题,我将其更改为结构。我最初的GetHashCode是在一个自定义EqualityComparer类中,我将其传递到linq的类中,但是,它为具有100%相同值的HashedFile获取不同的哈希值。感谢您的建议,是的,我确实希望比较文件字符串和哈希,但是使用list1运行此新结构。除了(list2),从未调用过public bool Equals,返回的列表又是list1。我将编辑答案,以包含一个在我的机器上运行的完整控制台示例,也许你可以发现我做了一些你错过的事情。真奇怪。。。使用您的示例,当我使用Except方法时,会调用Equals方法。。。但对于我的两个自定义字符串列表和一个16字节的数组,Equals方法永远不会被调用…嗯,看起来这可能是我的问题的一个因素,这里似乎是相关的。我只是做了一个快速测试,如果我将hashedFile更改为一个类Equals,它不会被命中,但它会作为一个结构,您的定义是什么?您的示例具有struct。
public struct hashedFile : IEquatable<hashedFile>
{
string _fileString;
byte[] _fileHash;
public hashedFile(string fileString, byte[] fileHash)
{
this._fileString = fileString;
this._fileHash = fileHash;
}
public string FileString { get { return _fileString; } }
public byte[] FileHash { get { return _fileHash; } }
public bool Equals(hashedFile other)
{
return _fileString == other._fileString && _fileHash.SequenceEqual(other._fileHash);
}
}
public class Program
{
public struct hashedFile : IEquatable<hashedFile>
{
string _fileString;
byte[] _fileHash;
public hashedFile(string fileString, byte[] fileHash)
{
this._fileString = fileString;
this._fileHash = fileHash;
}
public string FileString { get { return _fileString; } }
public byte[] FileHash { get { return _fileHash; } }
public bool Equals(hashedFile other)
{
return _fileString == other._fileString && _fileHash.SequenceEqual(other._fileHash);
}
}
public static void Main(string[] args)
{
List<hashedFile> list1 = GetList1();
List<hashedFile> list2 = GetList2();
List<hashedFile> diff = list1.Except(list2).ToList();
foreach (hashedFile h in diff)
{
Console.WriteLine(h.FileString + Environment.NewLine + h.FileHash[0].ToString("x2"));
}
Console.ReadLine();
}
private static List<hashedFile> GetList1()
{
hashedFile one = new hashedFile("test1", BitConverter.GetBytes(1));
hashedFile two = new hashedFile("test2", BitConverter.GetBytes(2));
hashedFile threeA = new hashedFile("test3", BitConverter.GetBytes(4));
hashedFile four = new hashedFile("test4", BitConverter.GetBytes(4));
var list1 = new List<hashedFile>();
list1.Add(one);
list1.Add(two);
list1.Add(threeA);
list1.Add(four);
return list1;
}
private static List<hashedFile> GetList2()
{
hashedFile one = new hashedFile("test1", BitConverter.GetBytes(1));
hashedFile two = new hashedFile("test2", BitConverter.GetBytes(2));
hashedFile three = new hashedFile("test3", BitConverter.GetBytes(3));
var list1 = new List<hashedFile>();
list1.Add(one);
list1.Add(two);
list1.Add(three);
return list1;
}
}
int hashCode = this.InternalGetHashCode(value);
for (int i = this.buckets[hashCode % this.buckets.Length] - 1; i >= 0; i = this.slots[i].next)
{
if ((this.slots[i].hashCode == hashCode) && this.comparer.Equals(this.slots[i].value, value))
{
return true;
}
}
public override int GetHashCode()
{
return 0;
}
public override int GetHashCode()
{
var hashCode = 0;
var bytes = _fileHash.Union(Encoding.UTF8.GetBytes(_fileString)).ToArray();
for (var i = 0; i < bytes.Length; i++)
hashCode = (hashCode << 3) | (hashCode >> (29)) ^ bytes[i]; // Rotate by 3 bits and XOR the new value.
return hashCode;
}