Warning: file_get_contents(/data/phpspider/zhask/data//catemap/8/linq/3.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# 重载Linq,但允许使用字节数组的自定义结构除外_C#_Linq_Struct_Operator Overloading_Except - Fatal编程技术网

C# 重载Linq,但允许使用字节数组的自定义结构除外

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

我在自定义结构和重载linq的except方法以删除重复项方面遇到问题

我的结构如下:

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;
}