2

I have a ConcurrentDictionary that I use as a hash table that will refresh at a regular time interval. the TValue of my ConcurrentDictionary is a custom class that I created :

public class RefreshableDictionaryValue<TValue>
{
    private DateTime lastRefreshed;
    private DateTime lastAccessed;
    private TValue value;

    public override bool Equals(object obj)
    {
        if (obj == null)
        {
            return false;
        }

        TValue t = (TValue)obj;
        if((System.Object)t == null)
        {
            return false;
        }

        return this.Value.Equals(((RefreshableDictionaryValue<TValue>)obj).Value);
    }
    public override int GetHashCode()
    {
        return Value.GetHashCode();
    }
    ...
}

I assume ConcurrentDictionary uses equals to compare values of two objects and I have overriden Equals for my class so that it returns true if the TValues are equal. The dates can be different. I also tried ineriting from IEqualityComparer<RefreshableDictionaryValue<TValue>> but that had no effect.

If I don't override Equals then TryUpdate returns false(obviously, cause the objects I'm comparing will have the same TValue but different dates) and if I do override equals I get this error

> Error while refreshing dictionary System.InvalidCastException: Unable
> to cast object of type
> ItemRefreshableDictionary.RefreshableDictionaryValue`1[StatsHelper.Stats]'
> to type 'StatsHelper.Stats'.    at
> ItemRefreshableDictionary.RefreshableDictionaryValue`1.Equals(Object
> obj) in
> \Projects\StatsHelper\ItemLevelRefreshableDictionary\ItemLevelRefreshableDictionary.cs:line
> 24    at System.Collections.Generic.ObjectEqualityComparer`1.Equals(T
> x, T y)    at
> System.Collections.Concurrent.ConcurrentDictionary`2.TryUpdate(TKey
> key, T Value newValue, TValue comparisonValue)

Edit: Here's how I do the update:

foreach(KeyValuePair<TKey, RefreshableDictionaryValue<TValue>> entry in cacheDictionary)
{
    DateTime lastRefresh = entry.Value.LastRefreshed;
    DateTime lastAccess = entry.Value.LastAccessed;

    secondsSinceLastRefresh = Convert.ToInt32((DateTime.Now - lastRefresh).TotalSeconds);
    secondsSinceLastAccess = Convert.ToInt32((DateTime.Now - lastAccess).TotalSeconds);
    if (secondsSinceLastAccess < cacheExpirationTime)
    {
        if (secondsSinceLastRefresh > refreshInterval)
        {
            TValue updatedValue = valueGetter(entry.Key);

            bool s = cacheDictionary.TryUpdate(entry.Key, new RefreshableDictionaryValue<TValue>(DateTime.Now, lastAccess, updatedValue), entry.Value);
        }
     }
 }
MarcinJuraszek
  • 124,003
  • 15
  • 196
  • 263
Adrian Buzea
  • 826
  • 2
  • 11
  • 33
  • `TValue t = (TValue)obj` should be replaced with `TValue t = obj as TValue` – MarcinJuraszek Jul 29 '15 at 07:30
  • I tried that (had to add where TValue:class to the class declaration). But now I'm getting an error when declaring the ConcurrentDictionary : private ConcurrentDictionary> cacheDictionary; // The type TValue must be a reference type in order to use it as parameter. Also I thought the 2 ways of doing the cast were equivalent – Adrian Buzea Jul 29 '15 at 07:33
  • @MarcinJuraszek if he does that, he needs a constraint – Mark Jul 29 '15 at 07:42
  • Ok so I added the constraint to all the classes that used RefreshableDictionaryValue and it works now but it doesn't work if TValue is an int for example. Anyway, TryUpdate still fails now so I assume that maybe it isn't using Equals for equality comparison ? – Adrian Buzea Jul 29 '15 at 07:46
  • 2
    Nevermind, just realized I was casting to a different type. This solves it: TValue t = (obj as RefreshableDictionaryValue).Value; – Adrian Buzea Jul 29 '15 at 07:54

0 Answers0