Export (0) Print
Expand All

KeyedCollection<TKey, TItem>.ChangeItemKey Method

Changes the key associated with the specified element in the lookup dictionary.

Namespace:  System.Collections.ObjectModel
Assemblies:   System.ObjectModel (in System.ObjectModel.dll)
  mscorlib (in mscorlib.dll)

protected void ChangeItemKey(
	TItem item,
	TKey newKey
)

Parameters

item
Type: TItem

The element to change the key of.

newKey
Type: TKey

The new key for item.

ExceptionCondition
ArgumentNullException

item is null.

-or-

key is null.

ArgumentException

item is not found.

-or-

key already exists in the KeyedCollection<TKey, TItem>.

This method does not modify the key embedded in item; it simply replaces the key saved in the lookup dictionary. Therefore, if newKey is different from the key that is embedded in item, you cannot access item by using the key returned by GetKeyForItem.

This method does nothing if the KeyedCollection<TKey, TItem> does not have a lookup dictionary.

Every key in a KeyedCollection<TKey, TItem> must be unique. A key cannot be null.

This method is an O(1) operation.

Notes for Implementers

Before modifying the key embedded in an item, you must call this method to update the key in the lookup dictionary. If the dictionary creation threshold is –1, calling this method is not necessary.

Do not expose the ChangeItemKey method as a public method of a derived class. Misuse of this method puts the lookup dictionary out of sync with item keys. For example, setting the key to null and then setting it to another value adds multiple keys for an item to the lookup dictionary. Expose this method internally to allow mutable item keys: When the key for an item changes, this method is used to change the key in the lookup dictionary.

The following code example shows how to override the protected ChangeItemKey method to support mutable keys, and how to override the protected InsertItem, RemoveItem, ClearItems, and SetItem methods to maintain the integrity of the keys and the collection.

The code example creates the MutableKeys collection, which derives from KeyedCollection<TKey, TItem>, and the MutableKey class. The MutableKey class has a settable Key property. When a new key is assigned to the property, the property setter calls the internal (Friend in Visual Basic) ChangeKey method of the collection to test whether the new key would conflict with an existing key. If so, an exception is thrown and the property value is not changed.

In order to maintain the connection between a MutableKey object and the MutableKeys collection and to prevent an object from being inserted into two collections, the MutableKey class has an internal (Friend in Visual Basic) Collection field. This field is maintained by the protected methods that provide custom behavior for adding and removing items from the collection, such as the InsertItem method. The field is set when the item is added to a collection and cleared when the item is removed.

using System;
using System.Collections.Generic;
using System.Collections.ObjectModel;

// This class demonstrates one way to use the ChangeItemKey 
// method to store objects with keys that can be changed. The  
// ChangeItemKey method is used to keep the internal lookup 
// Dictionary in sync with the keys of the stored objects.  
// 
// MutableKeys stores MutableKey objects, which have an Integer 
// Key property that can be set. Therefore, MutableKeys inherits 
// KeyedCollection(Of Integer, MutableKey). 
// 
public class MutableKeys : KeyedCollection<int, MutableKey>
{
    // This parameterless constructor delegates to the base class  
    // constructor that specifies a dictionary threshold. A 
    // threshold of 0 means the internal Dictionary is created 
    // the first time an object is added. 
    // 
    public MutableKeys() : base(null, 0) {}

    protected override int GetKeyForItem(MutableKey item)
    {
        // The key is MutableKey.Key. 
        return item.Key;
    }

    protected override void InsertItem(int index, MutableKey newItem)
    {
        if (newItem.Collection != null) 
            throw new ArgumentException("The item already belongs to a collection.");

        base.InsertItem(index, newItem);
        newItem.Collection = this;
    }

    protected override void SetItem(int index, MutableKey newItem)
    {
        MutableKey replaced = Items[index];

        if (newItem.Collection != null) 
            throw new ArgumentException("The item already belongs to a collection.");

        base.SetItem(index, newItem);
        newItem.Collection = this;
        replaced.Collection = null;
    }

    protected override void RemoveItem(int index)
    {
        MutableKey removedItem = Items[index];

        base.RemoveItem(index);
        removedItem.Collection = null;
    }

    protected override void ClearItems()
    {
        foreach( MutableKey mk in Items )
        {
            mk.Collection = null;
        }

        base.ClearItems();
    }

    internal void ChangeKey(MutableKey item, int newKey)
    {
        base.ChangeItemKey(item, newKey);
    }

    public void Dump()
    {
        Console.WriteLine("\nDUMP:");
        if (Dictionary == null)
        {
            Console.WriteLine("    The dictionary has not been created.");
        }
        else
        {
            Console.WriteLine("    Dictionary entries");
            Console.WriteLine("    ------------------");

            foreach( KeyValuePair<int, MutableKey> kvp in Dictionary )
            {
                Console.WriteLine("    {0} : {1}", kvp.Key, kvp.Value);
            }
        }

        Console.WriteLine("\n    List of items");
        Console.WriteLine("    -------------");

        foreach( MutableKey mk in Items )
        {
            Console.WriteLine("    {0}", mk);
        }
    }
}

public class Demo
{
    public static void Main()
    {
        MutableKeys mkeys = new MutableKeys();

        // The Add method is inherited from Collection. 
        //
        mkeys.Add(new MutableKey(110072674, "Widget"));
        mkeys.Add(new MutableKey(110072675, "Sprocket"));

        mkeys.Dump();

        Console.WriteLine("\nCreate and insert a new item:");
        MutableKey test = new MutableKey(110072684, "Gear");
        mkeys.Insert(1, test);

        mkeys.Dump();

        try
        {
            Console.WriteLine("\nTry to insert the item again:");
            mkeys.Insert(1, test);
        }
        catch(ArgumentException ex)
        {
            Console.WriteLine("Error: {0}", ex.Message);
        }

        Console.WriteLine("\nChange the Key property of the item:");
        test.Key = 100000072;

        mkeys.Dump();

        try
        {
            Console.WriteLine("\nTry to set the Key property to an existing key:");
            test.Key = 110072674;
        }
        catch(ArgumentException ex)
        {
            Console.WriteLine("Error: {0}", ex.Message);
        }

        mkeys.Dump();
    }

    private static void Display(MutableKeys order)
    {
        Console.WriteLine();
        foreach( MutableKey item in order )
        {
            Console.WriteLine(item);
        }
    }
}

// This class has a key that can be changed. 
//  
public class MutableKey
{

    public MutableKey(int newKey, string newValue)
    {
        _key = newKey;
        Value = newValue;
    } //New 

    public string Value;
    internal MutableKeys Collection;

    private int _key;
    public int Key    
    {
        get
        {
            return _key;
        }
        set
        {
            if (Collection != null)
            {
                Collection.ChangeKey(this, value);
            }

            _key = value;
        }
    }

    public override string ToString()
    {
        return String.Format("{0,9} {1}", _key, Value);
    }

}

/* This code example produces the following output:

DUMP:
    Dictionary entries
    ------------------
    110072674 : 110072674 Widget
    110072675 : 110072675 Sprocket

    List of items
    -------------
    110072674 Widget
    110072675 Sprocket

Create and insert a new item:

DUMP:
    Dictionary entries
    ------------------
    110072674 : 110072674 Widget
    110072675 : 110072675 Sprocket
    110072684 : 110072684 Gear

    List of items
    -------------
    110072674 Widget
    110072684 Gear
    110072675 Sprocket

Try to insert the item again:
Error: The item already belongs to a collection.

Change the Key property of the item:

DUMP:
    Dictionary entries
    ------------------
    110072674 : 110072674 Widget
    110072675 : 110072675 Sprocket
    100000072 : 100000072 Gear

    List of items
    -------------
    110072674 Widget
    100000072 Gear
    110072675 Sprocket

Try to set the Key property to an existing key:
Error: An item with the same key has already been added.

DUMP:
    Dictionary entries
    ------------------
    110072674 : 110072674 Widget
    110072675 : 110072675 Sprocket
    100000072 : 100000072 Gear

    List of items
    -------------
    110072674 Widget
    100000072 Gear
    110072675 Sprocket
 */

.NET Framework

Supported in: 4.6, 4.5, 4, 3.5, 3.0, 2.0

.NET Framework Client Profile

Supported in: 4, 3.5 SP1

Portable Class Library

Supported in: Portable Class Library

.NET for Windows Store apps

Supported in: Windows 8

Supported in: Windows Phone 8.1

Supported in: Windows Phone Silverlight 8.1

Supported in: Windows Phone Silverlight 8

Windows Phone 8.1, Windows Phone 8, Windows 8.1, Windows Server 2012 R2, Windows 8, Windows Server 2012, Windows 7, Windows Vista SP2, Windows Server 2008 (Server Core Role not supported), Windows Server 2008 R2 (Server Core Role supported with SP1 or later; Itanium not supported)

The .NET Framework does not support all versions of every platform. For a list of the supported versions, see .NET Framework System Requirements.

Show:
© 2014 Microsoft