Enhancing CAB’s ManagedObjectCollection

For those who don't know, the ManagedObjectCollection registers its elements using the objects running type as part of the key.

Recently, I had the need to add and retrieve a component to the WorkItem's Items collection independently of its running. I only wanted to retrieve the component (using a ComponentDependency) with a specified name. Needless to say that I couldn't, because I was trying to retrieve an object, and that was not the running type of the object added to the WorkItem.

I started thinking of the ability of the ServiceCollection to add items registering them with a different type would be very helpfully to the ManagedObjectCollection. So, decided to add some changes.

To be able to build elements and register them with a different type, I had to change the Build method: 

private TItem Build(Type typeToBuild, Type typeToRegisterAs, string idToBuild, object item)
{
	if (idToBuild != null && Contains(idToBuild, SearchMode.Local, true))
		throw new ArgumentException(String.Format(CultureInfo.CurrentCulture,
			Properties.Resources.DuplicateID, idToBuild));

	if (item != null && Object.ReferenceEquals(item,
		locator.Get(new DependencyResolutionLocatorKey(typeof(WorkItem), null))))
		throw new ArgumentException(Properties.Resources.CannotAddWorkItemToItself, "item");

	if (item == null)
		item = BuildFirstTimeItem(typeToBuild, typeToRegisterAs, idToBuild, null);
	else if (!container.Contains(item))
		item = BuildFirstTimeItem(typeToBuild, typeToRegisterAs, idToBuild, item);
	else
		BuildRepeatedItem(typeToBuild, typeToRegisterAs, idToBuild, item);

	return (TItem)item;
}

private object BuildFirstTimeItem(Type typeToBuild, Type typeToRegisterAs, string idToBuild, object item)
{
    item = builder.BuildUp(locator, typeToBuild, NormalizeID(idToBuild), item);

    if (typeToRegisterAs != typeToBuild)
    {
        locator.Add(new DependencyResolutionLocatorKey(typeToRegisterAs, idToBuild), item);
        locator.Remove(new DependencyResolutionLocatorKey(typeToBuild, idToBuild));
    }

    return item;
}

private void BuildRepeatedItem(Type typeToBuild, Type typeToRegisterAs, string idToBuild, object item)
{
    locator.Add(new DependencyResolutionLocatorKey(typeToRegisterAs, NormalizeID(idToBuild)), item);
}

And, to assure compability with the existing methods:

private TItem Build(Type typeToBuild, string idToBuild, object item)
{
    return Build(typeToBuild, typeToBuild, idToBuild, item);
}

Now, all I needed was to add the new methods to add elements:

public void Add(Type typeToRegisterAs, TItem item)
{
    Add(typeToRegisterAs, item, null);
}

public void Add(Type typeToRegisterAs, TItem item, string id)
{
    Guard.ArgumentNotNull(item, "item");
    Guard.TypeIsAssignableFromType(typeof(TItem), typeToRegisterAs, "typeToBuild");

    Build(typeToRegisterAs, item.GetType(), id, item);
}

public void Add<TTypeToRegisterAs>(TTypeToRegisterAs item)
    where TTypeToRegisterAs : TItem
{
    Add<TTypeToRegisterAs>(item, null);
}

public void Add<TTypeToRegisterAs>(TTypeToRegisterAs item, string id)
    where TTypeToRegisterAs : TItem
{
    Guard.ArgumentNotNull(item, "item");

    Build(item.GetType(), typeof(TTypeToRegisterAs), id, item);
}

public TItem AddNew(Type typeToBuild, Type typeToRegisterAs)
{
    Guard.TypeIsAssignableFromType(typeToBuild, typeToRegisterAs, "typeToBuild");

    return AddNew(typeToBuild, typeToRegisterAs, null);
}

public TItem AddNew(Type typeToBuild, Type typeToRegisterAs, string id)
{
    Guard.TypeIsAssignableFromType(typeToBuild, typeof(TItem), "typeToBuild");
    Guard.TypeIsAssignableFromType(typeToBuild, typeToRegisterAs, "typeToRegisterAs");

    return Build(typeToBuild, typeToRegisterAs, id, null);
}

public TTypeToBuild AddNew<TTypeToBuild, TTypeToRegisterAs>()
    where TTypeToRegisterAs : TItem
    where TTypeToBuild : TTypeToRegisterAs
{
    return (TTypeToBuild)Build(typeof(TTypeToBuild), typeof(TTypeToRegisterAs), null, null);
}

public TTypeToBuild AddNew<TTypeToBuild, TTypeToRegisterAs>(string id)
    where TTypeToRegisterAs : TItem
    where TTypeToBuild : TTypeToRegisterAs
{
    return (TTypeToBuild)Build(typeof(TTypeToBuild), typeof(TTypeToRegisterAs), id, null);
}

2 Responses to Enhancing CAB’s ManagedObjectCollection