I am trying to give out a IReadOnly-references to internal Collection objects.
This works well in most cases, but does not if i want to convert a dictionary containing a collection into an IReadOnlyDictionary containing a IReadOnlyCollection.
Here a code example:
var list = new List<int>();
IReadOnlyList<int> listReference = list; //works;
var dictionary = new Dictionary<int, int>();
IReadOnlyDictionary<int, int> dictionaryReference = dictionary; //works
var nestedList = new List<List<int>>();
IReadOnlyList<IReadOnlyList<int>> nestedReadOnlyListReference = nestedList; //works
var nestedDictionary = new Dictionary<int, List<int>>();
//IReadOnlyDictionary<int, IReadOnlyList<int>> nestedReadOnlyDictionaryReference = nestedDictionary; //does not work, can not implicitly convert
//current workaround
var nestedDictionaryReferenceHelper = new Dictionary<int, IReadOnlyList<int>>();
foreach (var kvpNestedDictionary in nestedDictionary)
{
nestedDictionaryReferenceHelper.Add(kvpNestedDictionary.Key, (IReadOnlyList<int>)kvpNestedDictionary.Value);
}
IReadOnlyDictionary<int, IReadOnlyList<int>> nestedReadOnlyDictionaryReference = nestedDictionaryReferenceHelper; //works, but is only a reference to the internal List, not to the dictionary itself
The workaround is pretty ugly as it needs additional memory and needs manual updating every time the values of nestedDictionary change.
Is there any simple way to convert such nested dictionaries?
In this SO question you can find a very good explanation why casting dictionary values is not supported. Please see the accepted answer of Eric Lippert.
Although i would not recommend this, you could use the following LINQ expression to cast the values of the dictionary to a read only list:
IReadOnlyDictionary<int, IReadOnlyList<int>> nestedReadOnlyDictionaryReference = nestedDictionary.ToDictionary(kv => kv.Key, kv => kv.Value as IReadOnlyList<int>);
It is a shorter version of your workaround and it is lazy evaluated, but i would not recommend this due to the following reasons:
This solution still creates a copy of the dictionary and does not update any new/deleted entries from the original dictionary.
The values of the dictionary, i.e. the readonly lists, refer to the original lists and changes there are updated in the read only versions in the dictionary too.
This is inconsistent behavior and therefore a bad practice!
Unless it is not possible to cast the values of a dictionary, i would not recommend doing this. You should either deep copy the entire dictionary including the nested lists, or use an other container that supports casting.
In my opinion the point is the you're missing the opportunity to introduce a proper new type with its own dignity. If you're using Dictionary<int, List<int>> then you will see yourself with code like this every time you need to insert a value:
if (!_dictionary.ContainsKey(key)) {
var list = new List<int>();
list.Add(value);
_dictionary.Add(key, list);
} else {
_dictionary[key].Add(value);
}
And even worse with code like this when you want to search for a value:
_dictionary.ContainsKey(key) && _dictionary[key].Contains(value);
And variation of those examples. What's worse you're exposing this implementation detail to your class users. If this detail will change then you will break all code. What, for example, if you want to replace List<int> with HashSet<int>?
How it should be?
_multimap.Add(key, value);
With a proper interface (here I show just few methods):
public interface IMultiMap<TKey, TValue> {
void Add(TKey key, TValue value);
bool ContainsKey(TKey key);
}
And its implementation:
public sealed class MultiMap<TKey, TValue> : IMultiMap<TKey, TValue> {
// ...
private Dictionary<int, List<int>> _items;
}
You can introduce IReadOnlyMultiMap<TKey, TValue>:
public interface IReadOnlyMultiMap<TKey, TValue> {
bool ContainsKey(TKey key);
}
Just implement IReadOnlyMultiMap<TKey, TValue> in MultiMap<TKey, TValue> and to return a read-only collection you have nothing to do (fictional example):
IReadOnlyMultiMap<int, int> MakeReadOnly(MultiMap<int, int> map) {
return map; // Nothing to do!
}
Note that you may want to introduce a new ReadOnlyMultiMap<TKey, TValue> to tunnel read calls to underlying live collection (to avoid callers to simply cast to MultiMap<TKey, TValue> to circumvent read-only limitation). Proof of concept:
public sealed class ReadOnlyMultiMap<TKey, TValue> : IReadOnlyMultiMap<TKey, TValue> {
public ReadOnlyMultiMap(IMultiMap<TKey, TValue> collection) {
_collection = collection;
}
public bool ContainsKey(TKey key) {
return _collection.ContainsKey(key);
}
private readonly IMultiMap<TKey, TValue> _collection;
}
To return a read-only view you do:
IReadOnlyMultiMap<int, int> MakeReadOnly(MultiMap<int, int> map) {
return new ReadOnlyMultiMap<int, int>(map);
}
Note that I talked about implementation detail. You're still exposing an implementation detail (you're using a multimap) then if such code is for a public API you should introduce a new (properly named) type to describe what it contains, not how storage is implemented. It may be MeasureCollection, SoccerScoreCollection or whatever your model is talking about, storage may vary but content won't.
Problem for conversion failing is the KeyValuePair:
Although class Derived inheriting class Base, KeyValuePair is not a sub class of KeyValuePair; see definitions(Dictionary, IReadOnlyDictionary).
So you always will need some kind of workaround (MultiMap approach appears to me as one, too...). If nestedDictionary is private, so you have complete control over it from your class, you might get away with this:
var nestedDictionary = new Dictionary<int, IReadOnlyList<int>>();
IReadOnlyDictionary<int, IReadOnlyList<int>> nestedReadOnlyDictionaryReference = nestedDictionary;
and whenever modifying a list within the dictionary applying a cast to List<int>. Another ugly workaround, I admit, but saves you extra memory and redundancy management and retains the (asumed...) public interface of IReadOnlyDictionary<int, IReadOnlyList<int>>.
Edit: just an idea, haven't tested, but it might work: Have your own dictionary adding the missing interfaces to be assignable to the read-only dictionary:
public class MyDictionary
: Dictionary<int, List<int>>,
ICollection<KeyValuePair<int, IReadOnlyList<int>>,
IEnumerable<KeyValuePair<int, IReadOnlyList<int>>,
IReadOnlyCollection<KeyValuePair<int, IReadOnlyList<int>>
{
}
I might yet have missed an interface to be implemented, and you might have to implement some members yet. If it works, possibly the cleanest solution...
Related
I have a quite odd question. I am working on a big project and i am implementing a core feature after millions of lines of code. I am not allowed to alter some parts of the code and it seems like i have to try this way.
I have two classes as A and B. A is derived from B.
public class B{}
public class A : B{}
I have a SortedList<string, A>, i need to cast the SortedList into List<B>. Operate on List<B> then cast the list into SortedList again.
For example:
SortedList<string, B> items;
public List<A> GetItems()
{
return items.Values.Cast<B>().ToList(); //Getting values works
}
public void SetItems(List<B> newItems)
{
items = CastWithMagic(newItems); //How to make casting work?
}
There are 2 possible changes on A items.
Changes on B(base class variables)
Removed items from the list.
I want to apply changes on List<B> to SortedList<string, A>
There are 2 possible changes on A items.
Changes on B(base class variables)
Removed items from the list.
Changes to the objects will be reflected in both lists, since the lists just contain references to the same objects. So all you should need to handle is objects that are deleted from the List. I believe you'll have to loop through the sorted list to see if the objects have been removed from the list:
public void SetItems(List<B> newItems)
{
foreach(string key in items.Keys)
{
if(!newItems.Contains(items[key] as B))
items.Remove(key);
}
}
Note that this is inefficient since you're looping through both collections, making it O(m*n) - if your collections are small and performance is not critical then you may be OK, but start with this and find ways to make it more efficient (maybe removing from the source collection instead of the copied list?)
You might be able to use Linq's 'select' function for this. Take this example code:
private void test()
{
List<alphaClass> firstList = new List<alphaClass>();
List<betaClass> secondList = firstList.Select(z => (betaClass)z).ToList();
}
public class alphaClass { }
public class betaClass : alphaClass { }
(This assumes everything from the list can be cast as the derived class.)
Anyway, linq's SELECT statement can be used to transform an IEnumerable into a different form. In this case, transforming it from one class to another.
EDIT: Whoops - missed the Sorted List part. That can be taken care of by using an extension method I found for a different question:
public static class ExtensionMethod
{
public static SortedList<TKey, TValue> ToSortedList<TSource, TKey, TValue>
(this IEnumerable<TSource> source,
Func<TSource, TKey> keySelector,
Func<TSource, TValue> valueSelector)
{
var ret = new SortedList<TKey, TValue>();
foreach (var element in source)
{
ret.Add(keySelector(element), valueSelector(element));
}
return ret;
}
}
... and then, from here, you can use that extension like this:
SortedList<string, betaClass> myList = new SortedList<string, betaClass>();
SortedList<string, alphaClass> secondList;
secondList = myList.ToSortedList(kvp => kvp.Key, kvp => (alphaClass) kvp.Value);
I am trying to give out a IReadOnly-references to internal Collection objects.
This works well in most cases, but does not if i want to convert a dictionary containing a collection into an IReadOnlyDictionary containing a IReadOnlyCollection.
Here a code example:
var list = new List<int>();
IReadOnlyList<int> listReference = list; //works;
var dictionary = new Dictionary<int, int>();
IReadOnlyDictionary<int, int> dictionaryReference = dictionary; //works
var nestedList = new List<List<int>>();
IReadOnlyList<IReadOnlyList<int>> nestedReadOnlyListReference = nestedList; //works
var nestedDictionary = new Dictionary<int, List<int>>();
//IReadOnlyDictionary<int, IReadOnlyList<int>> nestedReadOnlyDictionaryReference = nestedDictionary; //does not work, can not implicitly convert
//current workaround
var nestedDictionaryReferenceHelper = new Dictionary<int, IReadOnlyList<int>>();
foreach (var kvpNestedDictionary in nestedDictionary)
{
nestedDictionaryReferenceHelper.Add(kvpNestedDictionary.Key, (IReadOnlyList<int>)kvpNestedDictionary.Value);
}
IReadOnlyDictionary<int, IReadOnlyList<int>> nestedReadOnlyDictionaryReference = nestedDictionaryReferenceHelper; //works, but is only a reference to the internal List, not to the dictionary itself
The workaround is pretty ugly as it needs additional memory and needs manual updating every time the values of nestedDictionary change.
Is there any simple way to convert such nested dictionaries?
In this SO question you can find a very good explanation why casting dictionary values is not supported. Please see the accepted answer of Eric Lippert.
Although i would not recommend this, you could use the following LINQ expression to cast the values of the dictionary to a read only list:
IReadOnlyDictionary<int, IReadOnlyList<int>> nestedReadOnlyDictionaryReference = nestedDictionary.ToDictionary(kv => kv.Key, kv => kv.Value as IReadOnlyList<int>);
It is a shorter version of your workaround and it is lazy evaluated, but i would not recommend this due to the following reasons:
This solution still creates a copy of the dictionary and does not update any new/deleted entries from the original dictionary.
The values of the dictionary, i.e. the readonly lists, refer to the original lists and changes there are updated in the read only versions in the dictionary too.
This is inconsistent behavior and therefore a bad practice!
Unless it is not possible to cast the values of a dictionary, i would not recommend doing this. You should either deep copy the entire dictionary including the nested lists, or use an other container that supports casting.
In my opinion the point is the you're missing the opportunity to introduce a proper new type with its own dignity. If you're using Dictionary<int, List<int>> then you will see yourself with code like this every time you need to insert a value:
if (!_dictionary.ContainsKey(key)) {
var list = new List<int>();
list.Add(value);
_dictionary.Add(key, list);
} else {
_dictionary[key].Add(value);
}
And even worse with code like this when you want to search for a value:
_dictionary.ContainsKey(key) && _dictionary[key].Contains(value);
And variation of those examples. What's worse you're exposing this implementation detail to your class users. If this detail will change then you will break all code. What, for example, if you want to replace List<int> with HashSet<int>?
How it should be?
_multimap.Add(key, value);
With a proper interface (here I show just few methods):
public interface IMultiMap<TKey, TValue> {
void Add(TKey key, TValue value);
bool ContainsKey(TKey key);
}
And its implementation:
public sealed class MultiMap<TKey, TValue> : IMultiMap<TKey, TValue> {
// ...
private Dictionary<int, List<int>> _items;
}
You can introduce IReadOnlyMultiMap<TKey, TValue>:
public interface IReadOnlyMultiMap<TKey, TValue> {
bool ContainsKey(TKey key);
}
Just implement IReadOnlyMultiMap<TKey, TValue> in MultiMap<TKey, TValue> and to return a read-only collection you have nothing to do (fictional example):
IReadOnlyMultiMap<int, int> MakeReadOnly(MultiMap<int, int> map) {
return map; // Nothing to do!
}
Note that you may want to introduce a new ReadOnlyMultiMap<TKey, TValue> to tunnel read calls to underlying live collection (to avoid callers to simply cast to MultiMap<TKey, TValue> to circumvent read-only limitation). Proof of concept:
public sealed class ReadOnlyMultiMap<TKey, TValue> : IReadOnlyMultiMap<TKey, TValue> {
public ReadOnlyMultiMap(IMultiMap<TKey, TValue> collection) {
_collection = collection;
}
public bool ContainsKey(TKey key) {
return _collection.ContainsKey(key);
}
private readonly IMultiMap<TKey, TValue> _collection;
}
To return a read-only view you do:
IReadOnlyMultiMap<int, int> MakeReadOnly(MultiMap<int, int> map) {
return new ReadOnlyMultiMap<int, int>(map);
}
Note that I talked about implementation detail. You're still exposing an implementation detail (you're using a multimap) then if such code is for a public API you should introduce a new (properly named) type to describe what it contains, not how storage is implemented. It may be MeasureCollection, SoccerScoreCollection or whatever your model is talking about, storage may vary but content won't.
Problem for conversion failing is the KeyValuePair:
Although class Derived inheriting class Base, KeyValuePair is not a sub class of KeyValuePair; see definitions(Dictionary, IReadOnlyDictionary).
So you always will need some kind of workaround (MultiMap approach appears to me as one, too...). If nestedDictionary is private, so you have complete control over it from your class, you might get away with this:
var nestedDictionary = new Dictionary<int, IReadOnlyList<int>>();
IReadOnlyDictionary<int, IReadOnlyList<int>> nestedReadOnlyDictionaryReference = nestedDictionary;
and whenever modifying a list within the dictionary applying a cast to List<int>. Another ugly workaround, I admit, but saves you extra memory and redundancy management and retains the (asumed...) public interface of IReadOnlyDictionary<int, IReadOnlyList<int>>.
Edit: just an idea, haven't tested, but it might work: Have your own dictionary adding the missing interfaces to be assignable to the read-only dictionary:
public class MyDictionary
: Dictionary<int, List<int>>,
ICollection<KeyValuePair<int, IReadOnlyList<int>>,
IEnumerable<KeyValuePair<int, IReadOnlyList<int>>,
IReadOnlyCollection<KeyValuePair<int, IReadOnlyList<int>>
{
}
I might yet have missed an interface to be implemented, and you might have to implement some members yet. If it works, possibly the cleanest solution...
I have a Dictionary<string, List<string>> and would like to expose the member as read only. I see that I can return it as a IReadOnlyDictionary<string, List<string>>, but I can't figure out how to return it as an IReadOnlyDictionary<string, IReadOnlyList<string>>.
Is there a way to do this? In c++ I'd just be using const, but C# doesn't have that.
Note that simply using a IReadOnlyDictionary does not help in this case, because I want the values to be read only as well. It appears the only way to do this is build another IReadOnlyDictionary, and add IReadOnlyList to them.
Another option, which I wouldn't be thrilled with, would be to create wrapper which implements the interface IReadOnlyDictionary>, and have it hold a copy of the original instance, but that seems overkill.
It would be as easy as casting the whole dictionary reference to IReadOnlyDictionary<string, IReadOnlyList<string>> because Dictionary<TKey, TValue> implements IReadOnlyDictionary<TKey, TValue>.
BTW, you can't do that because you want the List<string> values as IReadOnlyList<string>.
So you need something like this:
var readOnlyDict = (IReadOnlyDictionary<string, IReadOnlyList<string>>)dict
.ToDictionary(pair => pair.Key, pair => pair.Value.AsReadOnly());
Immutable dictionaries
This is just a suggestion, but if you're looking for immutable dictionaries, add System.Collections.Immutable NuGet package to your solution and you'll be able to use them:
// ImmutableDictionary<string, ImmutableList<string>>
var immutableDict = dict
.ToImmutableDictionary(pair => pair.Key, pair => pair.Value.ToImmutableList());
Learn more about Immutable Collections here.
Given the fact that you're specifically looking for a read-only Dictionary<string, List<string>>, you're basically looking exactly for a Lookup.
The Dictionary object has a ToLookup() extension.
First, you'll have to create a new dictionary with the desired content types:
var dicWithReadOnlyList = dic.ToDictionary(
kv => kv.Key,
kv => kv.Value.AsReadOnly());
Then you can just return the new dictionary, since IReadOnlyDictionary is a supertype of Dictionary.
Why do you need to do that? Because Dictionary<T, A> is not a supertype of Dictionary<T, B>, even if A is a supertype of B. Why? Consider the following example:
var dic = new Dictionary<T, B>();
Dictionary<T, A> dic2 = dic; // Imagine this were possible...
dic2.Add(someT, someA); // ...then we'd have a type violation here, since
// dic2 = dic requires some B as the value.
In other words, TValue in Dictionary is not covariant. From an object-orientied point of view, covariance should be possible in the read-only version of the dictionary, but there are legacy issues in the .NET framework which prevent this (see the part starting with "UPDATE" in this question for details).
I run into the same problem. I solved it on the following way.
List<string> list = new List<string>();
Dictionary<string, IReadOnlyCollection<string>> dic = new Dictionary<string, IReadOnlyCollection<string>>();
IReadOnlyDictionary<string, IReadOnlyCollection<string>> dicRo = new ReadOnlyDictionary<string, IReadOnlyCollection<string>>(dic);
list.Add("Test1");
dic["T"] = list.AsReadOnly();
ist.Add("Test2");
This has the positiv effekt, that you
can still add items to the list
can still add items to the dictionary
can't edit the ReadOnlyDictionary
can't edit the ReadOnlyCollection
can't cast it into a Dictionary
can't cast it into a List
have your ReadOnlyDictionary always up to date
Maybe this will help someone.
If you want to return a read only dictionary but still be able to mutate the dictionary and list in your class you could use casting to get back the list type.
This example is a bit contrived, but shows how it could work.
public class MyClass
{
Dictionary<string, IReadOnlyList<string>> _dictionary;
public IReadOnlyDictionary<string, IReadOnlyList<string>> Dictionary { get { return _dictionary; } }
public MyClass()
{
_dictionary = new Dictionary<string, IReadOnlyList<string>>();
}
public void AddItem(string item)
{
IReadOnlyList<string> readOnlyList = null;
List<string> list = null;
if (!_dictionary.TryGetValue(item, out readOnlyList))
{
list = new List<string>();
_dictionary.Add(item, list);
}
else
list = readOnlyList as List<string>;
list.Add(item);
}
}
If you goal is to have the property be immutable, then using a ReadOnlyDictionary would be the best option.
https://msdn.microsoft.com/en-us/library/acdd6hb7.aspx
You can use this to expose the object as readonly.
You could also use properties get; set; and only allow the get to be public.
But Matias answer seems to be more fitting.
I have a generic dictionary that pass to a method which only accepts IQueryable as a parameter
Is it possible to cast the queryable back to the original dictionary? And I don't mean creating a new dictionary with .ToDictionary(...)
private static void Main()
{
var dict = new Dictionary<int, int>();
dict.Add(1,1);
SomeMethod(dict.AsQueryable());
}
public static void SomeMethod(IQueryable dataSource)
{
// dataSource as Dictionary<int, int> --> null
var dict = dataSource.???
}
I know in this simple example this does not make much sense. But in the big picture I have an interface which requires me to return an IQueryable as a dataSource. On implementation returns a dictionary. On a different place in my code I have classes that process the dataSources.
The processor knows that the dataSource will be an Dictionary but I don't want to have the overhead for creating another Dictionary if I already have one.
The .AsQueryable() extension method returns an instance of the EnumerableQuery<T> wrapper class if it is called on something that was not already an IQueryable<T>.
This wrapper class has an .Enumerable property with internal access that provides access to the original object that .AsQueryable() was called on. So you could do this to get back your original dictionary:
var dict = new Dictionary<int, int>();
dict.Add(1,1);
var q = dict.AsQueryable();
Type tInfo = q.GetType();
PropertyInfo pInfo = tInfo.GetProperties(BindingFlags.NonPublic |
BindingFlags.Instance)
.FirstOrDefault(p => p.Name == "Enumerable");
if (pInfo != null)
{
object originalDictionary = pInfo.GetValue(q, null);
Console.WriteLine(dict == originalDictionary); // true
}
However, this is generally a pretty bad idea. internal members have their access restricted for a reason, and I don't think there's any guarantee that the internal implementation of .AsQueryable() won't change at some point in the future. So your best bet is to either find a way to make the original dictionary accessible, or go ahead and make a new one.
One possible workaround (which is not great) is to make your own wrapper class to carry the dictionary along:
private class DictionaryQueryHolder<TKey, TValue> : IQueryable<KeyValuePair<TKey, TValue>>
{
public IDictionary<TKey, TValue> Dictionary { get; private set; }
private IQueryable<KeyValuePair<TKey, TValue>> Queryable { get; set; }
internal DictionaryQueryHolder(IDictionary<TKey, TValue> dictionary)
{
Dictionary = dictionary;
Queryable = dictionary.AsQueryable();
}
public IEnumerator<KeyValuePair<TKey, TValue>> GetEnumerator()
{
return Queryable.GetEnumerator();
}
IEnumerator IEnumerable.GetEnumerator()
{
return GetEnumerator();
}
public Expression Expression
{
get { return Queryable.Expression; }
}
public Type ElementType
{
get { return Queryable.ElementType; }
}
public IQueryProvider Provider
{
get { return Queryable.Provider; }
}
}
This would both act as a wrapper for the dictionary's IQueryable<T> and provide access to the original dictionary. But on the other hand, anyone trying to retrieve the dictionary would have to know what the generic type parameters were (e.g. <string, string>, <int, string>, etc.) in order to cast it successfully.
The main problem here is that IQueryable wraps itself around the Dictionary rather than being like IEnumerable<> over IDictionary<>, where you could cast it back.
You can certainly find out if the type wrapped is a dictionary if you know the types involved:
public bool isDictionary<T>(object obj) {
return obj.GetType().GenericTypeArguments.Contains(typeof(T));
}
isDictionary<KeyValuePair<string,string>>(dataSource);
If you don't mind reaching into the objects internals, you could use the private Enumerable field on EnumerableQuery to get a version of (possibly) the original dictionary back as an IEnumerable<>
But to actually convert from an EnumerableQuery<KeyValuePair<int,int>> hiding under an IQueryable without doing that I think you'd have to just take the hit and create a new dictionary from it.
I have the following method that makes a deep copy of a dictionary:
public static Dictionary<string, MyClass> deepCopyDic(Dictionary<string, MyClass> src)
{
//Copies a dictionary with all of its elements
//RETURN:
// = Dictionary copy
Dictionary<string, MyClass> dic = new Dictionary<string, MyClass>();
for (int i = 0; i < src.Count; i++)
{
dic.Add(src.ElementAt(i).Key, new MyClass(src.ElementAt(i).Value));
}
return dic;
}
I was wondering, can I somehow make it into a template? I need MyClass to be a template.
You can use Generics with where TValue : ICloneable constraint:
public static Dictionary<TKey, TValue> deepCopyDic<TKey, TValue>(Dictionary<TKey, TValue> src)
where TValue : ICloneable
{
//Copies a dictionary with all of its elements
//RETURN:
// = Dictionary copy
Dictionary<TKey, TValue> dic = new Dictionary<TKey, TValue>();
foreach (var item in src)
{
dic.Add(item.Key, (TValue)item.Value.Clone());
}
return dic;
}
You'll have to implement ICloneable interface in every class you'd like to pass into that method.
Or a bit improved version, with Key cloned as well:
public static Dictionary<TKey, TValue> deepCopyDic<TKey, TValue>(Dictionary<TKey, TValue> src)
where TValue : ICloneable
where TKey : ICloneable
{
return src.ToDictionary(i => (TKey)i.Key.Clone(), i => (TValue)i.Value.Clone());
}
You could use the copy constructor option:
Dictionary<string, int> copy = new Dictionary<string, int>(dictionary);
This way you make a deep copy of your dictionary.
Link to the original post.
The Serialized approach is the only way as noted above. ICloneable does not guarantee that all properties in the object being clone is not assigning references unless you have full control over the object which is never a good assumption, especially in a large team.
The only cavet of the Serialized approach is that all objects being passed in the dictionary are serializable. Also, serializing is not always very efficient because of the over use of Reflection that occurs, which shouldn't be used in high preformance areas of code.
I solved this problem using an approach known as fast serialization but it requires that all objects that you plan to clone support a specific interface. It's always speed vs. complexity.