2013-10-07 15 views
0

我有一個自定義結構和重載linq的除去方法刪除重複項的問題。重載Linq除了允許自定義結構與字節數組

我的結構如下:

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

    } 

此代碼顯示 「threeA」 和 「四有」 就好了。但是,如果我做了以下。

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

「diff」變成「list1」的精確副本。我還應該提到,我正在從System.Security.Cryptography.MD5中將ComputeHash的字節數組發送到列表中的字節文件哈希。

有關如何重載Except的Except或GetHashCode方法的任何想法,以成功地從列表2中排除重複的值?

我真的很感激它!謝謝! 〜MrFreeman

編輯:這是我最初是如何試圖用List<hashedFile> diff = newList.Except(oldList, new hashedFileComparer()).ToList();

class hashedFileComparer : IEqualityComparer<hashedFile> 
{ 

    public bool Equals(hashedFile x, hashedFile y) 
    { 
     if (Object.ReferenceEquals(x, y)) return true; 

     if (Object.ReferenceEquals(x, null) || Object.ReferenceEquals(y, null)) 
      return false; 

     return x.FileString == y.FileString && x.FileHash == y.FileHash; 
    } 

    public int GetHashCode(hashedFile Hashedfile) 
    { 
     if (Object.ReferenceEquals(Hashedfile, null)) return 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()); 
     } 

     return returnVal; 
    } 

} 
+0

採取的字節數組散列碼功能。如果上面的'HashedFile'類型的代碼就是所有你需要比行爲是正常的,因爲沒有'Equal' /'GetHashCode'(因爲數組和其他.NET集合一個沒有被比較的價值 - 所以你需要自己寫)。注意:當你想要一些痛苦時,使用'struct'往往是個人選擇,一定要明白你在做什麼。 –

+0

我重載了我自己的IEqualityComparer ,但它產生完全相同的結果。實際上,單步執行代碼時,甚至在使用Except方法時甚至不會觸及重載的「Equals」。 – MrFreeman

+0

爲什麼'HashedFile'是一個結構? –

回答

0

如果你想要的類型來處理自身的比較中,除非你需要的接口IEquatable。 IEqualityComparer接口要讓另一個類型處理比較,以便它可以傳遞到除了超載外。

這實現了你想要的(假設你想要文件字符串和哈希比較)。

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

這已成爲相當大的,但我會繼續存在與上述實施一個問題,如果hashedFile是一類不是結構(有時當stuct也許版本depdendant)。除了使用一個內部的Set類外,有問題的相關部分是它比較哈希碼,只有它們相等時,才使用比較器來檢查相等性。

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

此問題的解決方案取決於性能要求,您可以直接返回0哈希碼。這意味着比較器將始終被使用。

public override int GetHashCode() 
{ 
    return 0; 
} 

另一種選擇是,以生成正確的哈希碼本事項早於我的預期爲500項不同的是7毫秒VS 1毫秒和5000項爲650ms VS 13毫秒。所以可能最好使用適當的哈希碼。從https://stackoverflow.com/a/7244316/1002621

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

感謝您的建議,並且是的,我希望文件字符串和哈希比較,但是運行這個新的結構與list1.Except(list2),公共bool Equals永遠不會被調用,並且返回的列表再次只是list1。 – MrFreeman

+0

我要編輯答案,以包含可在我的機器上運行的完整控制檯示例,也許您可​​以發現我錯過的某些內容。 –

+0

有多奇怪......使用你的例子,Equals方法在我使用Except方法時被調用......但是用我的兩個自定義列表中的一個字符串和一個16字節的數組,Equals方法從未被調用...... – MrFreeman