/// <summary> /// Makes a deep clone of this bag. A new bag is created with a clone of /// each element of this bag, by calling ICloneable.Clone on each element. If T is /// a value type, then each element is copied as if by simple assignment. /// </summary> /// <remarks><para>If T is a reference type, it must implement /// ICloneable. Otherwise, an InvalidOperationException is thrown.</para> /// <para>Cloning the bag takes time O(N log N), where N is the number of items in the bag.</para></remarks> /// <returns>The cloned bag.</returns> /// <exception cref="InvalidOperationException">T is a reference type that does not implement ICloneable.</exception> public Bag <T> CloneContents() { bool itemIsValueType; if (!CollectionUtil.IsCloneableType(typeof(T), out itemIsValueType)) { throw new InvalidOperationException(string.Format(Strings.TypeNotCloneable, typeof(T).FullName)); } Hash <KeyValuePair <T, int> > newHash = new Hash <KeyValuePair <T, int> >(equalityComparer); // Clone each item, and add it to the new ordered bag. foreach (KeyValuePair <T, int> pair in hash) { KeyValuePair <T, int> newPair, dummy; T newKey; if (!itemIsValueType && pair.Key != null) { newKey = (T)(((ICloneable)pair.Key).Clone()); } else { newKey = pair.Key; } newPair = NewPair(newKey, pair.Value); newHash.Insert(newPair, true, out dummy); } return(new Bag <T>(equalityComparer, keyEqualityComparer, newHash, count)); }
/// <summary> /// Makes a deep clone of this set. A new set is created with a clone of /// each element of this set, by calling ICloneable.Clone on each element. If T is /// a value type, then each element is copied as if by simple assignment. /// </summary> /// <remarks><para>If T is a reference type, it must implement /// ICloneable. Otherwise, an InvalidOperationException is thrown.</para> /// <para>Cloning the set takes time O(N), where N is the number of items in the set.</para></remarks> /// <returns>The cloned set.</returns> /// <exception cref="InvalidOperationException">T is a reference type that does not implement ICloneable.</exception> public Set <T> CloneContents() { bool itemIsValueType; if (!CollectionUtil.IsCloneableType(typeof(T), out itemIsValueType)) { throw new InvalidOperationException(string.Format(Strings.TypeNotCloneable, typeof(T).FullName)); } Set <T> clone = new Set <T>(equalityComparer); // Clone each item, and add it to the new ordered set. foreach (T item in this) { T itemClone; if (itemIsValueType) { itemClone = item; } else { if (item == null) { itemClone = default(T); // Really null, because we know T is a reference type } else { itemClone = (T)(((ICloneable)item).Clone()); } } clone.Add(itemClone); } return(clone); }
/// <summary> /// Makes a deep clone of this dictionary. A new dictionary is created with a clone of /// each entry of this dictionary, by calling ICloneable.Clone on each element. If TKey or TValue is /// a value type, then each element is copied as if by simple assignment. /// </summary> /// <remarks><para>If TKey or TValue is a reference type, it must implement /// ICloneable. Otherwise, an InvalidOperationException is thrown.</para> /// <para>Cloning the dictionary takes time O(N log N), where N is the number of key-value pairs in the dictionary.</para></remarks> /// <returns>The cloned dictionary.</returns> /// <exception cref="InvalidOperationException">TKey or TValue is a reference type that does not implement ICloneable.</exception> public MultiDictionary <TKey, TValue> CloneContents() { bool keyIsValueType, valueIsValueType; // Make sure that TKey and TValue can be cloned. if (!CollectionUtil.IsCloneableType(typeof(TKey), out keyIsValueType)) { NonCloneableType(typeof(TKey)); } if (!CollectionUtil.IsCloneableType(typeof(TValue), out valueIsValueType)) { NonCloneableType(typeof(TValue)); } // It's tempting to do a more efficient cloning, utilizing the hash.Clone() method. However, we can't know that // the cloned version of the key has the same hash value. MultiDictionary <TKey, TValue> newDict = new MultiDictionary <TKey, TValue>(allowDuplicateValues, keyEqualityComparer, valueEqualityComparer); foreach (KeyAndValues item in hash) { // Clone the key and values parts. Value types can be cloned // by just copying them, otherwise, ICloneable is used. TKey keyClone; TValue[] valuesClone; if (keyIsValueType) { keyClone = item.Key; } else { if (item.Key == null) { keyClone = default(TKey); // Really null, because we know TKey isn't a value type. } else { keyClone = (TKey)(((ICloneable)item.Key).Clone()); } } valuesClone = new TValue[item.Count]; if (valueIsValueType) { Array.Copy(item.Values, valuesClone, item.Count); } else { for (int i = 0; i < item.Count; ++i) { if (item.Values[i] == null) { valuesClone[i] = default(TValue); // Really null, because we know TKey isn't a value type. } else { valuesClone[i] = (TValue)(((ICloneable)item.Values[i]).Clone()); } } } newDict.AddMany(keyClone, valuesClone); } return(newDict); }