private static void NodeRemove(object key, TypeDescriptionProvider provider)
{
lock (s_providerTable)
{
TypeDescriptionNode head = (TypeDescriptionNode)s_providerTable[key];
TypeDescriptionNode target = head;
TypeDescriptionNode prev = null;
while (target != null && target.Provider != provider)
{
prev = target;
target = target.Next;
}
if (target != null)
{
// We have our target node. There are three cases
// to consider: the target is in the middle, the head,
// or the end.
if (target.Next != null)
{
// If there is a node after the target node,
// steal the node's provider and store it
// at the target location. This removes
// the provider at the target location without
// the need to modify providers which may be
// pointing to "target".
target.Provider = target.Next.Provider;
// Now remove target.Next from the list
target.Next = target.Next.Next;
// If the new provider we got is a delegating
// provider, we can remove this node from
// the list. The delegating provider should
// always be at the end of the node list.
if (target == head && target.Provider is DelegatingTypeDescriptionProvider)
{
Debug.Assert(target.Next == null, "Delegating provider should always be the last provider in the chain.");
s_providerTable.Remove(key);
}
}
else if (target != head)
{
// If target is the last node, we can't
// assign a new provider over to it. What
// we can do, however, is assign a delegating
// provider into the target node. This routes
// requests from the previous provider into
// the next base type provider list.
// We don't do this if the target is the head.
// In that case, we can remove the node
// altogether since no one is pointing to it.
Type keyType = key as Type;
if (keyType == null) keyType = key.GetType();
target.Provider = new DelegatingTypeDescriptionProvider(keyType.GetTypeInfo().BaseType);
}
else
{
s_providerTable.Remove(key);
}
// Finally, clear our cache of provider types; it might be invalid
// now.
s_providerTypeTable.Clear();
}
}
}