2014-10-06 29 views
0

我有一個concurrentbag集合,我添加項目太..現在我可能最終會超過一個項目是相同的(由3個字符串屬性相等定義)ConcurrentBag不同

我不知道兩件事情。

  1. 如何生成的哈希碼出3個屬性
  2. 如果concurrengbag轉換到列表然後使用自定義的衍生比較器做一個明顯的上它是正確的方式..

的基本上目標是有可能包含重複然後在addcities方法cityProcessor財產NotFoundCities只能獲得非的DUP

public class CityProcesor 
{ 
    public ConcurrentBag<CityNotFound> NotFoundCities { get; set; } 
    public void AddCities() 
    { 
     var nonDups = NotFoundCities.ToList().Distinct(new NotFoundCityComparer()); 
    } 
} 
public class CityNotFound 
{ 
    public string Name { get; set; } 
    public string RegionName { get; set; } 
    public string CountryCode { get; set; } 
} 
public class NotFoundCityComparer : IEqualityComparer<CityNotFound> 
{ 
    public bool Equals(CityNotFound city1, CityNotFound city2) 
    { 
     return city1.Name == city2.Name && city1.RegionName == city2.RegionName && city1.CountryCode == city2.CountryCode; 
    } 
    public int GetHashCode(CityNotFound obj) 
    { 

     return 1; //TODO: fix 
    } 
} 
+0

ConcurrentBag是一個非常特殊的集合,它使用線程本地存儲來確保每個線程快速訪問它創建的值。它不是HashSet的併發版本。你確定這是你想要的嗎? – 2014-10-06 15:07:27

+0

使用concurrentbag的原因是因爲多個線程正在添加到相同的集合 – Zoinky 2014-10-06 15:08:30

+0

正如我所說,這不是*它應該用於什麼。當您在ConcurrentBag上執行'ToList()'時,您將快速獲得調用線程創建的項目並等待其他項目。您可以使用ConcurrentDictionary或甚至是ConcurrentQueue來描述您所描述的場景。你必須在這兩種情況下重寫'GetHashCode' – 2014-10-06 15:11:36

回答

1

不是impleme列表nt EqualsGetHashCode您可以使用Jon Skeet的MoreLinqDistinctBy擴展方法,該方法可用作源代碼或作爲NuGet Package提供。

隨着DistinctBy你可以寫:

var noDups=myCities.DistinctBy(city=> 
           new {city.Name,city.RegionName,city.CountryCode}); 

要實現GetHashCode你比較器裏面,你可以使用任何算法,將返回一個適度寬範圍值 - 它並不一定是唯一的。

public override int GetHashCode() 
    { 
     unchecked 
     { 
      var hashCode = (Name != null ? Name.GetHashCode() : 0); 
      hashCode = (hashCode*397)^(RegionName != null ? RegionName.GetHashCode() : 0); 
      hashCode = (hashCode*397)^(CountryCode != null ? CountryCode.GetHashCode() : 0); 
      return hashCode; 
     } 
    } 
+0

這是一個很棒的擴展,謝謝我會給那一個嘗試 – Zoinky 2014-10-06 15:44:20

0

我用於生成散列如下:

下面的代碼片段使用ReSharper的模板和異或每個屬性的哈希碼,例如創建。我不記得在那裏我發現我基於它的算法(可能在計算器上的某個地方),但我把它分爲以下幾個實用工具類和方法能夠創建多個字段/屬性哈希:

public static class HashGenerator 
{ 
    private const int seed = 29; 
    private const int factor = 31; 

    /// <summary> 
    /// Method to generate a hash code from multiple objects. 
    /// This can be used when overriding GetHashCode by passing in an object's key fields 
    /// </summary> 
    public static int GetHashCodeFromMany(params object[] objects) 
    { 
     unchecked 
     { 
      int hashCode = seed; 
      int length = objects.Length; 
      for (int counter = 0; counter < length; counter++) 
      { 
       object obj = objects[counter]; 
       if (obj != null) 
       { 
        int objHashCode = obj.GetHashCode(); 
        hashCode *= factor + objHashCode; 
       } 
      } 
      return hashCode; 
     } 
    } 
} 

然後可以使用這樣的:

public override int GetHashCode() 
{ 
    return HashGenerator.GetHashCodeFromMany(Name, RegionName, CountryCode); 
} 

這是最好的與不可變對象使用它,否則,改變的重點領域/屬性可能會導致混亂與同時使用散列的集合類。