3

I know how to convert a ConcurrentDictionary to a Dictionary.

And I know that I can use reflection to determine if an object contains a ConcurrentDictionary.

But after I determined that an object does have a ConcurrentDictionary via reflection, how do I convert it to a Dictionary at runtime? Or can I do it at all? It's going to change the definition of the class, right?

Edit: I should have made it more clear. I'll show an example:

    [Serializable]
    [DataContract]
    public class CacheItem
    {
        [DataMember]
        private ConcurrentDictionary<string, CacheItemEntity> _cacheItemDictionary = new ConcurrentDictionary<string, CacheItemEntity>();

        ......
    }

When I serialize an instance of this class, AVRO can't serialize the ConcurrentDictionary. So I wondered if I can convert the ConcurrentDictionary to a normal Dictionary at runtime. And this certainly changes the definition of the class. I'm just wondering if it can be done this way.

Allen Zhang
  • 2,432
  • 2
  • 20
  • 31
  • 2
    What is the motivation for wanting to convert the type? – jdphenix Apr 29 '15 at 05:23
  • @jdphenix, to be able to serialize objects that contain ConcurrentDictionary via microsoft AVRO library. – Allen Zhang Apr 29 '15 at 05:26
  • `var newDictionary = yourConcurrentDictionary.ToDictionary(kvp =>vp.Key, kvp => kvp.Value);` – Damith Apr 29 '15 at 05:26
  • `var dictionary = new Dictionary(concurrentDictionary);`? – Yuval Itzchakov Apr 29 '15 at 05:26
  • You can use `ToDictionary()` or the appropriate constructor of `Dictionary` as mentioned in comments. It's not really "converting" it though, but creating a new collection from a copy. If that's a good solution for you – jdphenix Apr 29 '15 at 05:29
  • @jdphenix I dont think he's looking for a deep clone. – Yuval Itzchakov Apr 29 '15 at 05:30
  • @Damith: perhaps you should cast yourConcurrentDictionary to ConcurrentDictionary first, since its type is known only at runtime. – Victor Mukherjee Apr 29 '15 at 05:32
  • 2
    Your question is confusing, because you've said you know how to do A, and you know how to do B, but you want to know how to do B then A. Is the problem *actually* that you don't know the type arguments at compile-time, due to using reflection? What do you mean by "change the definition of the class" - are you trying to change the type of the field itself? It would really help if you could make this a lot clearer... – Jon Skeet Apr 29 '15 at 05:36
  • DataContractSerializer (used by AVRO I believe) can serialize ConcurrentDictionary AFAIK. Why do you need to change it to Dictionary? – danish Apr 29 '15 at 07:51
  • @danish, it can't. I confirmed it with Microsoft. – Allen Zhang Apr 29 '15 at 20:42
  • @JonSkeet, I edited my question. Hopefully it cleared things up a little. – Allen Zhang Apr 29 '15 at 20:49
  • This sounds like it's quite an Avro-specific question - so that should be in your tags... my guess is that you should be implementing some specific serialization code. – Jon Skeet Apr 29 '15 at 20:51
  • @JonSkeet, the motivation is AVRO. But I wonder if doing such thing is possible or not. – Allen Zhang Apr 29 '15 at 20:59
  • Changing the type of a field (not just the value, but the actual *type* of a field)? Nope, basically not. Not unless you want to unload the appdomain, fiddle with the IL and reload it... – Jon Skeet Apr 29 '15 at 21:00
  • [This question](http://stackoverflow.com/questions/18955441/how-to-serialize-deserialize-immutable-list-type-in-c-sharp)'s answers may have some useful advice in them. [This answer](http://stackoverflow.com/a/18957739/15880) in particular. – Powerlord Apr 29 '15 at 21:00

1 Answers1

3

ConcurrentDictionary<TKey, TValue> implements IDictionary<TKey, TValue> so anyplace you are trying to use a "dictionary" you can use the interface instead. For example:

void ConsumeIDictionary(IDictionary dic)
{
   //perform work on a dictionary, regardless of the concrete type
}

You could call the method like this and it would be fine:

ConsumeIDictionary(new ConcurrentDictionary<int,int>());

Alternatively if you have a method that you want to use that requires the concrete Dictionary<TKey,TValue> type, then you can use the Dictionary constructor that takes an existing IDictionary:

void ConsumeDictionary<K,V>(Dictionary<K,V> dic)
{
   //perform work on a concrete Dictionary
}

Then call it like this:

ConsumeDictionary(
   new Dictionary(
       new ConcurrentDictionary<int,int>()));

Just be aware that calling this constructor is an O(n) operation.

If you are trying to using reflection, you can determine that an object is a ConcurrentDictionary by examining the object's type at runtime via GetType():

bool IsConcurrentDictionary<k, v>(obj o)
{
    return o.GetType() == typeof(ConcurrentDictionary<k,v>);
}

But in this case you may want to forget about the generic type parameters and just check for the IDictionary interface:

bool IsDictionary(obj o)
{
    return o is IDictionary;
}
Matthew Strawbridge
  • 19,940
  • 10
  • 72
  • 93
Philip Pittle
  • 11,821
  • 8
  • 59
  • 123